Конференция "WinAPI" » Лажа с округлениями??? [D7, WinXP]
 
  • DimDim (10.11.08 12:02) [0]
    Уважаемые Мастера! Первый раз с таким столкнулся и вполном замешательстве...
    В таблице:
    PoleCena : Float = 2,5
    PoleKol : Float = 0,046
    PoleSumma : Float (Calculated) := Round(PoleCena*PoleKol*100)/100

    Комп1: PoleSumma = 0,12
    Комп2: PoleSumma = 0,11
    Комп3: PoleSumma = 0,11

    Программа установлена на Комп1. На комп2 и Комп3 запускается по сети.
    Комп1 и Комп2 абсолютно одинаковые (покупались в один день с одинаковыми версиями винды и с тех пор не переустанавливалась).
    На моем копьютере PoleSumma = 0,11
    Это что?
  • Anatoly Podgoretsky © (10.11.08 12:10) [1]
    > DimDim  (10.11.2008 12:02:00)  [0]

    Это может какая ни будь программа, которая меняет маску.
  • DimDim (10.11.08 12:41) [2]
    Причем здесь маска? Я программно округляю до 2-х знаков после запятой.
    Программа, меняющая математику процессора?
    Компьютер - это усовершенствованый калькулятор. Как можно поменять в принципе незыблимые в природе законы математики? Я понимаю, что для компьютера 2*2 = примерно 4. Но законы округления на едентичных машинах должны быть одинаковые...
  • Сергей М. © (10.11.08 12:48) [3]

    > DimDim


    Программа твоя ?

    Тогда непосредственно перед вызовом Round вызови GetRoundMode и посмотри режим округления
  • DimDim (10.11.08 13:01) [4]
    Программа моя.
    Закзчик (где эта х... проявилась) далековато.
    С GetRoundMode ниразу не сталкивался. Что она дает? Можно поподробней?
    Да и толку что я узнаю режим округлений? Бороться с этим как?
  • Сергей М. © (10.11.08 13:07) [5]

    > Закзчик ..далековато.


    Это твоя личная драма.


    > Что она дает? Можно поподробней?


    см. справку, там все написано.


    > толку что я узнаю режим округлений?


    Как минимум подтвержишь или опровергнешь факт того, что разные экз-ры твоей программы на разных машинах используют при округлении разные его режимы, из-за чего отличаются результаты округления
  • DimDim (10.11.08 13:09) [6]
    Да и мне, собственно, по барабану в какую сторону она 5 округляет - лижбы у всех одинаково округляла...
  • Сергей М. © (10.11.08 13:23) [7]

    > лижбы у всех одинаково округляла


    Тогда проверяй региональные установки у каждого пользователя.
  • Anatoly Podgoretsky © (10.11.08 14:35) [8]
    > DimDim  (10.11.2008 13:01:04)  [4]

    www.intel.com архитектура процессора.
  • Anatoly Podgoretsky © (10.11.08 14:36) [9]
    > DimDim  (10.11.2008 13:09:06)  [6]

    Тогда обеспечить у всех одинаковую среду
  • DimDim (10.11.08 22:26) [10]
    Ну, про региональные установки - это первое что пришло на мысль. Но там ведь нихр... похожего нет. Да и быть не может. Даже в африке 2*2=4.  Если какая-то настройка и есть, то где-то на уровне биоса.

    > Тогда обеспечить у всех одинаковую среду
    Пользуется программой 400 заказчиков (около 1000 компов). ИЗДЕВАЕТЕСЬ???

    Попробую переписать процедуры округлений в такой вид:
    Round((PoleCena*PoleKol*100)+0.0000000000000001)/100
    может поможет. Буду надеяться, что это не повлияет на другие вычисления.

    Но все равно это не правильно! У меня в корне подорвана вера в вычислительную технику! Один и тот же расчет, сделаный на разных компах может дать разные результаты? Бред...
  • Anatoly Podgoretsky © (10.11.08 23:02) [11]
    > DimDim  (10.11.2008 22:26:10)  [10]

    Бред, при одинаковых условиях - результаты одинаковые.
  • DimDim (11.11.08 01:28) [12]
    Какие нах... условия в элементарной математике!???
    Или может от каких-то условий теорема Пифагора может поменяться?

    Я сам свято верил что такого быть не может! Пока мне заказчики пальцем не показали.
  • Сергей М. © (11.11.08 08:51) [13]

    > DimDim   (11.11.08 01:28) [12]


    И чего ты разнахался ?)
    Не трожь элементарную математику - в ней еще и не такие чудеса происходят)

    Вот тебе пища для размышления:


    procedure TForm1.Button1Click(Sender: TObject);
    type
    //  Float = Double; // <- сначала раскомментируй эту строчку
    //  Float = Single; // <- а теперь эту
    const
     PoleCena : Float = 2.5;
     PoleKol : Float = 0.046;
    var
     PoleSumma: Float;
    begin
     PoleSumma := Round(PoleCena*PoleKol*100)/100;
     ShowMessage('Результат без маски: ' + FloatToStr(PoleSumma) + ' , Результат с маской: ' + FormatFloat('# ##0.00', PoleSumma));
    end;



    Удивись и задумайся над тем ЧТО на самом деле есть Float-тип поля дейтасета на каждом из рассматриваемых тобой компах)
  • DimDim (11.11.08 12:17) [14]
    Все это понятно. И наглядней это будет так:

    procedure TForm1.Button1Click(Sender: TObject);
    type
     //Float = Double; // <- сначала раскомментируй эту строчку
     Float = Single; // <- а теперь эту
    const
    PoleCena : Float = 2.5;
    PoleKol : Float = 0.046;
    var
    PoleSumma: Float;
    begin
    Label1.Caption:=FloatToStr(PoleCena);
    Label2.Caption:=FloatToStr(PoleKol);
    PoleSumma := Round(PoleCena*PoleKol*100)/100;
    Label3.Caption:='Результат без маски: ' + FloatToStr(PoleSumma) +
      ' , Результат с маской: ' + FormatFloat('# ##0.00', PoleSumma);
    end;



    И ты хочешь сказать, что "Результат без маски" на разных компьютерах может <> 0,119999997317791 из-за каких-то настроек?
    Ну, я бы мог это понять, если бы один и тот расчет выполнялся в разных вариантах программы с разными типами переменных.
    В принципе, очень поучительный пример с точки зрения общей теории. А делать-то чаво? Узнал от заказчика много интересного о себе... Их теория не интересует - их интересует достоверность расчета.
  • Сергей М. © (11.11.08 12:40) [15]
    Я хочу сказать только одно : видимый результат (с маской или без маски - индифферентно) так или иначе зависит от формата хранения и представления чисел с п/з - как операндов, так и результата.

    Вероятно, следует сосредоточиться на исследовании среды функционирования СУБД, с которой работает твоя программа - именно она поставляет для TFloatField-операндов данные в формате чисел с п/з . Один клиент получает их в виде Single-типа и видит в результате дальнейших вычислений один результат, а другой клиент получает, скажем, Double-тип и видит, как ты уже убедился, другой результат.


    > Узнал от заказчика много интересного о себе


    И он прав - ты как разработчик должен был предвидеть такую ситуацию .. или же принять меры к идентичности СУБД-среды
  • Anatoly Podgoretsky © (11.11.08 15:27) [16]
    > DimDim  (11.11.2008 12:17:14)  [14]

    Не настроек, а масок процессора - контрольное слово процессора. Обычное дело, из-за твоего коды ты обязан был рано или позно попасть, поскольку код предполагает эту "ошибку". Нафиг делать такое кривое округление до двух, которое к тому же бессмысленно без маски вывода в f-FormatFloat поскольку float это число с плавающей запятой и системе глубоко пофиг на твои изращения. Почитай на Королевстве, что это такое.
  • DimDim (12.11.08 00:34) [17]
    Я отлично понимаю что такое число с плавающей точкой и почему одно и то же число в разных типах переменных не равны.
    "Такое кривое округление" делается не от хорошей жизни, а потому что от результата делается еще мульен вычислений. Причем, в расчетах он печатается как промежуточный. Отображать через маску не округленный результат - тогда лажа (точнее - не понятные заказчику числа) вылазят в дальнейшем расчете.
    Программа по расчету сметной стоимости строительства. Конечные расчеты (сметы, акты и т.д.) проверяются двумя сторонами - кто их составляет и для кого они составляются. Проверяют обычно от одного промежуточного результата до другого. ПРОВЕРЯЮТ КАЛЬКУЛЯТОРОМ! И при проверке смотрят на промежуточные результаты ИЗ РАСПЕЧАТКИ. Каждому не объяснишь что в распечатке предполагаются точные числа. А уж тем более что на одном компе посчитано с точностью Extended, а на другом, почему-то, с точность Single. Поэтому КАЖДЫЙ промежуточный результат (который выводится в распечатки) приходится явным образом округлять, чтобы избежать лишних вопросов. Я уже молчу, что в программе предусмотрена пользовательская система настройки точности вычислений...
    Если бы результат округления был бы некий конечный результат, который распечатать и забыть - то проблемы бы небыло - однозначно FormatFloat.
  • Anatoly Podgoretsky © (12.11.08 00:46) [18]
    > DimDim  (12.11.2008 0:34:17)  [17]

    Но в твоих примерах, не в расчете, а простой вывод на метку.
    Если нужна абсолютная точность, то надо использовать точные, а не приблизительные числа, не Float, а BCD, в крайнем случае Currency.
    Но ведь и в этом случае операции не коммутативны. A/B * B <> A, попробуй 1/2*3 c промежуточными результатами.
    Расчеты на калькуляторы тоже дадут разные числа, в зависимости с промежуточными результатами или нет.
  • DimDim (12.11.08 11:22) [19]
    Да не нужна мне абсолютная точность. Пусть считает как угодно. Вопрос-то в том, чтобы на разных мопьютерах получался один и тот же результат.

    Здесь http://www.delphikingdom.com/asp/viewitem.asp?catalogid=374 говорится о команде "Set8087CW(Get8087CW or $0100)" и др. Она может жестко установить точность вычислений для конкретной программы? Как она используется? Можно ли ее прописать в процедуре Create главной формы и свято верить что она установит правила вычислений для данной программы?
  • Григорьев Антон © (12.11.08 16:16) [20]

    > Можно ли ее прописать в процедуре Create главной формы и
    > свято верить что она установит правила вычислений для данной
    > программы?

    Нет. Любой вызов внешней функции теоретически может изменить управляющее слово процессора. Лучше делать такой вызов непосредственно перед каждым блоком вычислений.

    Кстати, в современных версиях Delphi в модуле Math появилась более удобная функция для этих целей - SetPrecisionMode.

    Кроме того, эта команда влияет только на режим точности, но не влияет на режим округления. Для его установки в Math есть ещё одна функция - SetRoundMode, она тоже вам может пригодиться.
 
Конференция "WinAPI" » Лажа с округлениями??? [D7, WinXP]
Есть новые Нет новых   [134435   +33][b:0][p:0.001]