double
в C не представляет все возможные числа, которые могут быть выражены в тексте.
double
может типично представлять около 2 разные номера. Ни 34000000.535
, ни 33000000.535
находятся в этом наборе, когда double
кодируется как номер binary floating point. Вместо этого используется самое близкое представимое число.
Text 34000000.535
closest double 34000000.534999996423...
Text 33000000.535
closest double 33000000.535000000149...
С double
в виде двоичного числа с плавающей точкой, умножения на не-включения питания из-2, как 100,0, могут вводить дополнительные различия округления. Тем не менее, в этих случаях все еще возникают продукты, один чуть выше xxx.5, а другой ниже.
Добавление 0.5
, простая мощность 2, не вызывает проблем округления, поскольку значение не является экстремальным по сравнению с 3x00000053.5.
Проведение промежуточных результатов для высокоточной точности показа показывает типичный поэтапный процесс.
#include <stdio.h>
#include <float.h>
#include <math.h>
void fma_test(double a, double b, double c) {
int n = DBL_DIG + 3;
printf("a b c %.*e %.*e %.*e\n", n, a, n, b, n, c);
printf("a*b %.*e\n", n, a*b);
printf("a*b+c %.*e\n", n, a*b+c);
printf("a*b+c %.*e\n", n, floor(a*b+c));
puts("");
}
int main(void) {
fma_test(34000000.535, 100, 0.5);
fma_test(33000000.535, 100, 0.5);
}
Выход
a b c 3.400000053499999642e+07 1.000000000000000000e+02 5.000000000000000000e-01
a*b 3.400000053499999523e+09
a*b+c 3.400000053999999523e+09
a*b+c 3.400000053000000000e+09
a b c 3.300000053500000015e+07 1.000000000000000000e+02 5.000000000000000000e-01
a*b 3.300000053500000000e+09
a*b+c 3.300000054000000000e+09
a*b+c 3.300000054000000000e+09
Вопрос является более сложным, то это простые ответы, как различные платформы могут 1) использовать более высокую точность математику, как long double
или 2) редко используют десятичной с плавающей точкой double
. Таким образом, результаты кода могут отличаться.
Проблемы с округлением, конечно, используйте библиотеку для произвольной математики точности (например, gmp), если вам нужны точные вычисления. – Ctx
Потому что вы имеете дело с бинарной плавающей точкой. – cHao
@cHao Обратите внимание, что даже с _decimal_ [с плавающей запятой] (https://en.wikipedia.org/wiki/Decimal64_floating-point_format) такие проблемы могут возникать со значениями, близкими к пределам точности формата. Таковы свойства арифметики с плавающей запятой, в любой базе. Это, безусловно, более распространено с десятичным текстом и двоичным 'double'. – chux