C++Builder
  Начало   Форум   Помощь Войти Регистрация  
Страниц: [1]   Вниз
  Печать  
Автор Тема: Странное преобразование...  (Прочитано 3354 раз)
d7d1cd
Участник


Сказали спасибо: +59/-24
Offline

Сообщений: 1005


Странное преобразование...
« : 03 Август 2013, 18:41:55 »

Привет всем. Подскажите, почему в ниже приведенном коде в переменной bbb появляется значение 52, а не 53?
Код
UnicodeString sss = L"5,3";
double ddd = sss.ToDouble();
BYTE bbb = ddd * 10;
 
Записан
POV
Участник


Сказали спасибо: +107/-7
Offline

Сообщений: 640


Re: Странное преобразование...
« Ответ #1 : 04 Август 2013, 18:36:54 »

Видимо точное представление числа не 5.3, а 5.29999999
Записан
d7d1cd
Участник


Сказали спасибо: +59/-24
Offline

Сообщений: 1005


Re: Странное преобразование...
« Ответ #2 : 04 Август 2013, 22:11:41 »

Цитата: POV от 04 Август 2013, 18:36:54
Видимо точное представление числа не 5.3, а 5.29999999
Представим что так. Но тогда почему такой код дает верный результат?
Код
UnicodeString sss = L"5,3";
double ddd = sss.ToDouble();
ddd *= 10;
BYTE bbb = ddd;
 
Записан
POV
Участник


Сказали спасибо: +107/-7
Offline

Сообщений: 640


Re: Странное преобразование...
« Ответ #3 : 04 Август 2013, 23:13:32 »

Дык, компилер может (а может и должен?), зная тип результата, привести все к нему. Потому и вычисления по разному производятся.
Записан
Rius
Давний друг


Сказали спасибо: +116/-5
Offline

Сообщений: 753


Re: Странное преобразование...
« Ответ #4 : 05 Август 2013, 05:11:26 »

Если хотите предопределённого результата, пользуйтесь функциями ceil, floor, modf из .
Записан
d7d1cd
Участник


Сказали спасибо: +59/-24
Offline

Сообщений: 1005


Re: Странное преобразование...
« Ответ #5 : 05 Август 2013, 20:37:24 »

Мне совсем не понятно почему получается так:
Код
UnicodeString sss = L"5,3";
double ddd = sss.ToDouble(); //сейчас у нас ddd = 5.3
int aaa = ddd *10; //тут aaa = 52
ddd *= 10; //сейчас ddd = 53
 
Записан
Rius
Давний друг


Сказали спасибо: +116/-5
Offline

Сообщений: 753


Re: Странное преобразование...
« Ответ #6 : 05 Август 2013, 20:42:25 »

//сейчас у нас ddd = 5.3
Вы так в этом уверены? Ответ был дан ещё во втором сообщении темы

Есть 5.300000190734863 и 5.299999237060547. А у вас что на самом деле?
Записан
d7d1cd
Участник


Сказали спасибо: +59/-24
Offline

Сообщений: 1005


Re: Странное преобразование...
« Ответ #7 : 05 Август 2013, 22:22:04 »

Цитата: Rius от 05 Август 2013, 20:42:25
Есть 5.300000190734863 и 5.299999237060547. А у вас что на самом деле?

У меня 5,3! Извините за выражение, но по кой хрен тогда придуман тип double - число двойной точности?!  Явно не для того чтобы хранить "то ли 5,3000000343434", "то ли 5,299999999343434".
Записан
Rius
Давний друг


Сказали спасибо: +116/-5
Offline

Сообщений: 753


Re: Странное преобразование...
« Ответ #8 : 05 Август 2013, 22:25:59 »

С чего вы взяли, что у вас 5.3??? Уж не с текстового ли вывода в строку или в отладчике, который делает округление по ему одному известному алгоритму?
На тот хрен придумали, что программисты, знающие об особенностях чисел в плавающей точкой, могли пользоваться более сложными вычислениями. Не хотите об этому задумываться - используйте аналоги Decimal (из C#) или создайте своё, с целочисленными частями слева и справа от точки.

Извиняюсь, опечатка.
Да, чтобы хранить не "то ли 5,3000000343434, то ли 5,299999999343434", т.к. это single - float.
А чтобы хранить "то ли 5.29999999999999982236431605997495353221893310546875, то ли 5.300000000000000710542735760100185871124267578125", здесь знаков побольше.
Можете тут поиграться с этим форматом: IEEE-754 Analysis
« Последнее редактирование: 05 Август 2013, 23:01:16 от Rius » Записан
d7d1cd
Участник


Сказали спасибо: +59/-24
Offline

Сообщений: 1005


Re: Странное преобразование...
« Ответ #9 : 09 Август 2013, 21:46:25 »

Получается, что если я в программе переменную одного типа присваиваю переменной другого типа умноженной на какое-то число, то могу получить потерю точности, даже если этого совсем не ожидается?
Записан
Rius
Давний друг


Сказали спасибо: +116/-5
Offline

Сообщений: 753


Re: Странное преобразование...
« Ответ #10 : 09 Август 2013, 21:58:05 »

Выполняйте явно преобразование типа с предсказуемым результатом, и всё будет ожидаемо.
Ну и от чисел с плавающей точкой чудес не ждите.

Хотя они бывают, например
Код
float a = какая-то "удачная" математическая операция>;
float b = константа>;
if (a b)
{
}
else if (a > b)
{
}
else if (a == b)
{
}
else
{
// думаете сюда никогда не дойдёт?
// а нет, иногда доходит!
}
 
Записан
POV
Участник


Сказали спасибо: +107/-7
Offline

Сообщений: 640


Re: Странное преобразование...
« Ответ #11 : 09 Август 2013, 22:38:03 »

Цитата: Rius от 09 Август 2013, 21:58:05
// думаете сюда никогда не дойдёт?
// а нет, иногда доходит!

Серьезно? Я преимущественно прогарммлю для мелких микроконтроллеров - там точность сравнения флоатов настраивается до компиляции. Как тут может быть 4-е состояние из трех возможных?

Я понимаю, что "константа" будет отличаться от того, что написано в коде и результат будет не очевиден при отладке. Но выход за пределы трёх решений смущает.

P.S. Я категорически против запоминания приоритетов операций. Всегда не ленюсь ставить лишние фигурные скобки:
Код
if (a  b)
{
}
else
{ // уже больше или равно
if (a == b)
{
}
else
{
}
}

Может это косяк кода, а не представления чисел?
« Последнее редактирование: 09 Август 2013, 22:44:47 от POV » Записан
Rius
Давний друг


Сказали спасибо: +116/-5
Offline

Сообщений: 753


Re: Странное преобразование...
« Ответ #12 : 09 Август 2013, 22:40:14 »

Нелогично, необъяснимо, очень-очень-очень редко, невоспроизводимо, но бывает. Причина, как я догадываюсь, в пограничных представлениях чисел с плавающей точкой, компиляторе, может и в текущих флагах процессора.
Константа это лишь пример. В самом сравнении чисел может что-то произойти такое.
Записан
POV
Участник


Сказали спасибо: +107/-7
Offline

Сообщений: 640


Re: Странное преобразование...
« Ответ #13 : 09 Август 2013, 22:41:15 »

Я чуток подправил своё недоумение выше.
Записан
Rius
Давний друг


Сказали спасибо: +116/-5
Offline

Сообщений: 753


Re: Странное преобразование...
« Ответ #14 : 09 Август 2013, 22:55:18 »

Больше склоняюсь с ошибкам (не программиста) в работе с плавающими точками, из-за компилятора или в процессоре, на пограничных условиях.
Возможно, пункт 9.5 Ошибки на границе норма/денорма числа.
Кстати, d7d1cd будет полезно почитать про ошибки, часть 9 статьи.
Записан
Rius
Давний друг


Сказали спасибо: +116/-5
Offline

Сообщений: 753


Re: Странное преобразование...
« Ответ #15 : 12 Август 2013, 07:20:24 »

Один из вариантов оказался очень простой 

Код
#include "stdafx.h"
#include
#include
 
int _tmain(int argc, _TCHAR* argv[])
{
float a = 0;
float b = 0;
float c = a / b;
float g = 1.0f;
 
if (c g)
{
printf("c \n"
);
}
else if (c > g)
{
printf("c > g \n");
}
else if (c == g)
{
printf("c == g \n");
}
else
{
printf("c ? g \n"); //
}
 
getchar();
return 0;
}
Причина - "Invalid Operation" в IEEE 754, вызываемая в том числе сравнением, в котором одно из чисел == NaN.
Записан
d7d1cd
Участник


Сказали спасибо: +59/-24
Offline

Сообщений: 1005


Re: Странное преобразование...
« Ответ #16 : 13 Август 2013, 20:55:53 »

То есть, код
Код
float a = 0;
float b = 0;
float c = a / b;
а именно 3 строка не вызывает ошибку? Ну да, ведь в b у нас не 0...
Записан
Rius
Давний друг


Сказали спасибо: +116/-5
Offline

Сообщений: 753


« Ответ #17 : 13 Август 2013, 21:00:34 »

В b именно 0, ведь для нуля в IEEE-754 предусмотрен специальный код. Там, правда, есть +0 и -0, но это не важно.
Также предусмотрено NaN, которое получается в результате такого деления.

Цитировать
Стандарт описывает:
    Определения форматов хранения мантиссы, показателя и знака, форматы положительного и отрицательного нуля, плюс и минус бесконечностей, а также определение «не числа» (NaN).
    Методы, которые используются для преобразования числа в процессе математических операций.
    Обработку исключительных ситуаций, таких как деление на нуль, переполнение, потеря значимости, работу с денормализованными числами и т.д.
    Операций: арифметические и другие операций по арифметике форматов.
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  




....

Powered by SMF 1.1.21 | SMF © 2025, Simple Machines
Страница сгенерирована за 0.124 секунд. Запросов: 21.