Конференция "KOL" » Проблема с функциями Extended2Str и Str2Extended [Delphi, Windows]
 
  • Grademax (25.02.11 13:31) [0]
    Если у кого есть желание и время разобраться с проблемой (для меня не актуально, случайно наткнулся), то суть в следующем:

    Дано простое выражение: 107.3-105.4 = 1.9 (так должно получиться)
    Танцы с бубном показали:

    Вариант 1 (выдает верный результат) [= 1.9]

    uses kol;
    var a:Extended;
    begin
        a:=107.3-105.4;
        MsgOk(Extended2Str(a));
    end.



    Вариант 2 (выдает неверный результат) [= 1.89999999999999]

    uses kol;
    var a:Extended;
       s1,s2:String;
    begin
        s1:='107.3';
        s2:='105.4';
        a:=Str2Extended(s1) - Str2Extended(s2);
        MsgOk(Extended2Str(a));
    end.



    Причем, если подставить другие числа - в 99,999% всё будет расчитано верно даже по второму варианту!

    P.S.
    Так же второй вариант выдает:
    10007.3-10005.4 = 1.89999999999964
    100007.3-100005.4 = 1.90000000000873
    ну и т.д.
  • Mr (25.02.11 14:10) [1]
    Ей-богу детский сад. Модераторы перенесите в соответствующую ветку.
  • Bingo (25.02.11 14:49) [2]
    Ради спортивного интереса ввёл выражение 100007.3-100005.4 в программу "НИК-Калькулятор" (Для тех кто не знает - Строчный Калькулятор для проектирование инженерный систем - очень популярная программа ксати), получил ответ 1.900000000009. Во прикол!

    Примечание... "НИК-Калькулятор" написан на Delphi (без использования KOL).! Возникает логичный вопрос: может в самих Дельфях с математикой что-то не в порядке?
  • Vladimir Kladov © (25.02.11 20:38) [3]
    Уверяю Вас, Вы получите не менее странный результат, работая с десятичными числами, хранящимися в двоичной системе, независимо от языка программирования. Значение 1.8999... это очень точное значение к тому результату, который получился после преобразования операндов в двоичное представления, и вычитания их в двоичной системе по правилам двоичной арифметики - в пределах доступной разрядности. Вы не знали, что далеко не всякую конечную десятичную дробь можно представить в виде двоичного с плавающей запятой?

    Конкретный совет: прибавьте к результату малое число, например 0.000000002. Затем переведите в 10-ю систему. Затем отбросьте десятичные знаки после '.', кроме первых семи. Теперь можете отбросить завершающие нули. У Вас получится точное представление, за минусом ошибки в седьмом знаке после запятой. Да, если число отрицательное, исходную прибавку нужно вычитать.

    Почему я не делаю такую функцию. На все случаи жизни этот метод не годится. Вот вам потребовалось работать с числами порядка 1000000, и с точностью 1 знак после запятой. В случае другого порядка чисел нужна будет другая прибавка, округление до другого знака после запятой. В Вашем случае, кстати, почему бы не работать сразу с числами, масштабированными на порядок, т.е. с целыми, а затем просто впихнуть символ точки перед единицами при отображении результата.

    Вы можете попробовать встроенную стандартную процедуру Str. Кстати, неплохо работает, хотя требует больше кода.

    Если требуется избежать вообще всех ошибок, связанных с переходом из 10-тичной системы в 2-чную и обратно, следует вычисления с плавающей запятой выполнять сразу в 10-тичной системе. На сайте KOL есть модуль DecimalCalculations, который позволяет работать с десятичными дробями с точностью до 100 знаков, при желании модифицируется, и там уже до стольки знаков, сколько в память влезет. Скорость, правда, значительно ниже, поскольку это фактически эмулятор калькулятора. И кода так же поболее будет, чем Extended2Str. Да и пользоваться неудобнее будет, в смысле программировать сами вычисления. Но если надо, то почему бы и нет.
  • GradeMax (26.02.11 07:35) [4]
    Спасибо, Владимир, за развернутый и доходчивый ответ.
    Без шуток... На многие вещи глаза открылись.
 
Конференция "KOL" » Проблема с функциями Extended2Str и Str2Extended [Delphi, Windows]
Есть новые Нет новых   [120350   +21][b:0][p:0.001]