Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.135.205.164] |
|
Сообщ.
#1
,
|
|
|
Здравствуйте.
Проблема выглядит так: procedure TForm1.FormCreate(Sender: TObject); var tmpReal: Real; begin tmpReal := (100/20000*1526)*100; ShowMessage(IntToStr(trunc((100/20000*1526)*100))+' - '+IntToStr(trunc(tmpReal))); end; Этот код даст разные сообщения при компиляции W32 и W64. Подскажите, пожалуйста, почему так? ЗЫЖ проверялось да Д10.2 и Д10.3. Если вы не верите или не хотите проверять, вот как это выглядит: https://www.youtube.com/watch?v=9fdip3DVReQ . |
Сообщ.
#2
,
|
|
|
Потому что у тебя не указан тип применяемый в первой матоперации в ShowMessage. По всей видимости разночтения пошли из-за того что дельфи, рассчитав значение еще на этапе компиляции, использовала разные типы.
Ну как пример: - Extended for 32bit - Double for 64bit (в 64 битах строго говоря Extended из коробки не поддерживается). |
Сообщ.
#3
,
|
|
|
Есть где-то упоминание этого в документации Эмбы?
Строго говоря, посчитав это на калькуляторе, получаем что минимальный используемый разряд мантиссы - 3, а разница в результате порождена во втором разряде. То есть погрешность от одной сотой до одной тысячной. Но ведь если погрешность расчётов так высока, то как тогда пишется огромное количество софта на Дельфях? Чем этот пример особенный? Чем эти цифры особенные? |
Сообщ.
#4
,
|
|
|
Rouse прав насчёт расчёта на этапе компиляции - в win32 загружается константа 762
00791750 B8FA020000 mov eax,$000002fa >если погрешность расчётов так высока Нет, если забыть о куче особенностей вещественных чисел. Далеко не все числа точно представимы во float И в Win32 c ними работает сопроцессор, а в Win64 в основном SSE-модуль (без Extended), поэтому могут быть некоторые отклонения. |
Сообщ.
#5
,
|
|
|
Сама ситуация обнаружена когда эти цифры внутри переменных. Повторяемость ситуации с константами как бы намекает что проблема не в константе.
А что за особенности вещественных чисел и при чём тут они? (если я правильно помню что такое вещественное число) В данном примере на каждом шаге вычислений всегда получается рациональное число. И если бы Float или Extended не мог точно хранить число 0.005 (а именно такое значение минимально при проведении расчётов), то поехало бы в страну вечной охоты 90% вычислений. Помогите, пожалуйста, понять чем этот пример особенный. |
Сообщ.
#6
,
|
|
|
>на каждом шаге вычислений всегда получается рациональное число.
Вещественные точно представляют только некоторые рациональные числа >если бы Float или Extended не мог точно хранить число 0.005 Дык не может... https://www.h-schmidt.net/FloatConverter/IEEE754.html Value actually stored in float: 0.004999999888241291046142578125 В данном случае поможет Round вместо Trunc (если логика подходит) Вот почитать: http://www.delphikingdom.com/asp/viewitem.asp?catalogid=374 https://docs.oracle.com/cd/E19957-01/806-35...g_goldberg.html |
Сообщ.
#7
,
|
|
|
Поэкспериментировал с Round и Trunc и всё стало на свои места...
Если подробно, возможный теоретический худший вариант, когда все компоненты при расчётах являются приближениями: 99.(9)/19999.(9)*1525.(9)*99.(9) = 762.(9) Trunc и Round тут предсказуемо дадут разный результат. Но по хорошему, скорей всего, приближением представляется только тот результат расчётов, который без явной типизации. Спасибо за подсказку, пошёл правильно исправлять . |
Сообщ.
#8
,
|
|
|
А ту т есть вообще необходимость в таком порядке вычислять? Ведь при вычислении только в целых числах
100*1526*100 div 20000 |
Сообщ.
#9
,
|
|
|
Вообще эта плавающая точка тот еще зверек.
Давеча вылезла ошибка у одного из клиентов, казалось бы обычное число 8.07875. Но если это число было в Double и его присвоить переменной типа Currency то под 64 бита получим 8.0788, а под 32 - 8.0787 и дальше все рассчеты поплывут Случайно наткнулись. Выкрутится конечно можно примерно так: function ConvertDoubleToCurrency(Value: Double): Currency; begin Value := Value * 10000; Result := Round(Value) / 10000; end; Но есть еще неявные преобразования, поэтому похоже придется использовать кастомные типы и все преобразования делать через "class operator Implicit/Explicit" |