Pull to refresh
0
0
Спиридонов Юрий Маркович @Innotor

Изобретатель

Send message
Думаю, ответ такой. Не использовать в расчетах с действительными (рациональными) числами двоичную арифметику в том виде, как она реализована в стандарте. Причем не важно, как она реализована, на аппаратном или на программном уровне. Вся беда в том, что проблемы начинаются, когда десятичное число содержит дробную часть. Целые числа не приводят к ошибкам представления. Поэтому, если представлять числа в виде ЧПТ с целочисленной мантиссой, эти проблемы не возникают. Возникают другие проблемы, но они не системные и преодолимы. Попытка ответить на ваш вопрос была предпринята в моем топике https://habrahabr.ru/post/272251/. В комментариях можно найти ссылку на PDF-файл.
Для точных вычислений существует двоично-десятичный формат, который реализует десятичную арифметику.
А как учитывать, если из заявленной точности — 15 достоверных цифр после запятой для нормализованных чисел формата double, верными оказываются только 7?
Разница между двумя числами double a = 0.66 и double b = 0.659999996423721 составляет 0,000000003576279. Вопрос, какое должно быть EPSILON, чтобы убедиться, что это число равно числу 0.00000000357627905067659

на сколько полезна ваша серия статей (аж в год длинной) про недостатки текущего стандарта?


Ну, статья не про IEEE754, а об ошибках, которые получаются в результате арифметических операций при использовании двоичной арифметики для десятичных ЧПТ. Эти ошибки не совсем очевидны, так как в большом количестве случаев результаты вычислений будут верными при использовании стандарта. Но где гарантия, что мы не столкнемся именно с теми немалочисленными ситуациями, когда будут получены совершенно неприемлемые результаты.
В статье речь идет ни об ошибках в Excel, а проблемах работы с ЧПТ, которые представлены в двоичном коде. Excel был взят для иллюстрации.
Ваш юмор я оценил. Но как быть с расчетами?
Вот программка, которую по моей просьбе написал Дмитрий Пикулик.
/*
* gcc -O0 -Wall -msoft-float -o test test.c
*/
#include <stdio.h>
#include <assert.h>
#include <float.h>
#include <math.h>

static double f(double a, double b)
{
double r = a — b;

return r;
}

int main (int argc, char **argv)
{
double a = 0.66;
double b = 0.659999996423721;

x = f(a, b);

printf(«x=%.40f\n», x);

return 0;
}

x=0.00000000357627905067658 95770513452589512 ≈0.00000000357627905067659

Сравните с тем, что получится на калькуляторе.
Ну, про точность хвоста, мы ничего не можем сказать, нам про него ничего не известно.
Математики, которым критичен этот хвост, и так в курсе того, что компьютер может хранить лишь конечное множество всех возможных значений, в курсе мантисс и экспонент, и в курсе различий между численным и аналитическим решением уравнения
.
Но, позвольте, а как пользователю относиться к тому, что мы получаем на выходе Excel? Математики может и в курсе, что некоторые числа могут получаться неточными. А как пользователю определить, когда можно доверять результату, а когда нет?
И вот когда мы отбрасываем двоичный хвост, возвращаясь к double или float, тут и вырастает десятичный хвост, который все и портит.
Да, на выходе FPU происходит усечение двоичного представления числа. Но именно усечение двоичного числа и приводит к появлению хвоста, значение которого априори определить не представляется возможным. А за счет нормализации часть хвоста оказывается в области ожидаемых верных цифр.
К сожалению я не нашел этого очень старого учебника и поэтому ничего возразить не могу.
Если Вас устраивает экономия памяти, при которой вы получаете результат с относительной погрешностью 0.6% на одной операции, то конечно проблем не будет.
0,0056-0,005599976 =0,005599976/105.3256 ≈0,006*100=0.6%
В учебниках же пишут про float и double, что они не точные.

Да, это всем известно. Но в статье речь идет не об ошибках преобразования десятичных чисел в двоичные и обратно, а к последствиям, к которым эти преобразования приводят при простейших арифметических вычислениях.
Именно этот факт и приводит к тем ошибкам, о которых в статье говорится.
" Все ваши примеры эксплуатируют один и тот же эффект: не каждая конечная десятичная дробь является конечной дробью в двоичной системе счисления. Тут как бы на IEEE754 не стоит всех собак вешать. Скорее, следует сетовать на конечность представления чисел (каким бы оно не было)".


Вы совершенно правы. И про IEEE754 вы правы. Стандарт работает с теми числами, которые ему предлагают. Но как Excel понять, где правильное число, а где не правильное. Если в большинстве случаев на выходе правильный результат, а в некоторых, случайных, не правильный, как быть?
2) Получить при вычислениях непредсказуемые результаты, конечно можно, если вы используете неустойчивые алгоритмы.

Но почему же Excel использует неустойчивый алгоритм стандарта IEEE754 для сложения, вычитания и проч. Если на выходе мы имеем непредсказуемый результат?
Дайте ссылку, где эта проблема рассматривается в таком контексте.
В статье речь идет о результатах арифметических вычислений действительных десятичных чисел с использованием двоичной арифметики.
Извините, я сразу не понял о каком алгоритме идет речь. В алгоритме, который я предлагаю, нет разницы между нормализованными и ненормализованными числами. Поэтому нет особого случая. Все числа обрабатываются одинаково. В том же случае, когда порядок числа по абсолютной величине превышает максимальное значение, которое может он принимать, наступает переполнение.
О каком алгоритме идет речь? Если не использовать специально нормализацию, то работа с нормализованными и денормализованными числами ничем не будет отличаться. Они будут обрабатываться по одним и тем же алгоритмам.

Information

Rating
Does not participate
Location
Минск, Минская обл., Беларусь
Registered
Activity