Видимо, ваша арифметическая ошибка не сразу вам понятна.Позвольте мне изложить это по буквам.
Предположим, что двойник состоит из двух частей: большой и малой, каждая из которых имеет точность примерно 32 бита.(Это не совсем то, как удваивается работа, но это подойдет для наших целей.)
У поплавка есть только одна часть.
Представьте, что мы делали это 32 бита за раз, но все держалиудваивается:
double divisor = whatever;
double dividend = dividendbig + dividendlittle;
double bigquotient = dividendbig / divisor;
Что такое большой коэффициент?Это двойной.Так что у него есть две части.bigquotient равно bigquotientbig + bigquotientlittle.Продолжая:
double littlequotient = dividendlittle / divisor;
снова, маленький коэффициент - маленький коэффициент большой + маленький коэффициент - маленький.Теперь мы добавим коэффициенты:
double quotient = bigquotient + littlequotient;
Как мы можем это вычислить?частное имеет две части.Соотношение будет установлено на BigquotientBig.частное маленькое будет установлено как большое частное + маленькое частное.littlequotientlittle отбрасывается.
Теперь предположим, что вы делаете это поплавками.У вас есть:
float f1 = dividendbig;
float f2 = dividendlittle;
float r1 = f1 / divisor;
ОК, что такое r1?Это поплавок.Так что это только одна часть.r1 - большое число.
float r2 = f2 / divisor;
Что такое r2?Это поплавок.Так что это только одна часть.r2 малозначно.
double result = (double)r1 + (double)r2;
Вы складываете их вместе и получаете большой коэффициент + маленький коэффициент большой. Что случилось с bigquotientlittle? Вы потеряли 32 бита там, и поэтому неудивительно, что вы получите неточности 32 бита на этом пути. Вы вообще не придумали правильный алгоритм для аппроксимации 64-битной арифметики в 32 битах.
Чтобы вычислить (big + little)/divisor
, вы не можете просто сделать (big / divisor) + (little / divisor)
.Это правило алгебры не применяется, когда вы округляете во время каждого деления!
Теперь понятно?