Перейти к содержанию
    

Не работает правильно, вычисление float в Keil

Код округление числа до десятых.

 

float x = 0;

 

x = 401 * 0.0625; //25.0625

x = x * 10; //250.625

x = x + 0.5; //251.125

x = floor(x); //251

x = x / 10; // Ошибка!

 

При делении 251 на 10, вроде должно быть 25.1, а получается 25.0999995.

Если float поменять на double, работает. Но, в маем случае очень не удобно использовать double.

Код в другой среде, работает и с float.

Понято, что происходит потеря точности.

 

Может есть другой способ округлить число до десятых.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

попробуйте поделить на 10.0

или умножить на 0.1f

Изменено пользователем Herz
Избыточное цитирование

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Понято, что происходит потеря точности.
или число 25.1 невозможно представить типом float с принятым у кейла размером мантиссы. Проверьте просто x = 25.1;

 

не слушайте psL, он продемострировал незнание основ языка.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Код округление числа до десятых.

. . . .

Может есть другой способ округлить число до десятых.

Решение через нетоместо, но решение.

Используйте sprintf c указанием точности, напр. %12.1f

ps

ну и исходник (s)printf можно посмотреть.

 

Изменено пользователем k155la3

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

При делении 251 на 10, вроде должно быть 25.1, а получается 25.0999995.

Кому должно? не должно оно никому. Почитайте представление чисел в float'e, поймете- там величина всегда неточная, она просто в заданном точностью диапазоне. Кстати, по этой же причине грубой ошибкой является попытка проверить float на равенство чему-то.

У Вас просто проявилась накопленная во время вычислений (всех вычислений, а не только последнего!) ошибка.

 

Собственно Вы сами уже ответили на свой вопрос:

 

Если float поменять на double, работает.

...

Понято, что происходит потеря точности.

 

Вас смутило что "Код в другой среде, работает и с float.". Скорее всего, в этой "другой среде" (уж не Матлаб ли?) оно приводится к длинному представлению и в нем считается, вот и все.

 

Эти ошибки представления не такой очевидный факт. Я лет 15 назад пытался это же объяснить девушке (Программистка, только что окончила Московский Энергетический, очень круто было в наших краях), у нее была ошибка: если она кучу коротких данных (импульсы от счетчиков) преобразовывала в киловатт-часы, то месячная сумма этих коротких величин не сходилась с данными, показанными по барабану счетчика (конец минус начало интервала наблюдения). Причем если взять сумму импульсов за месяц и преобразовать в киловатты, то с барабаном совпадало.

Она так и не поняла про точность вычислений, у нее же писи и фокспро, они всегда точно считают. Думала что я над ней так прикалываюсь. :)

 

И не бойтесь использовать дабл, ничего страшного в нем нет.

 

Upd: вот первое попавшееся неплохое описание вопроса. Например, интересен пункт "4.2 Неассоциативность арифметических операций", но там много и другого интересного про подводные камни плавающей точки.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

или число 25.1 невозможно представить типом float с принятым у кейла размером мантиссы. Проверьте просто x = 25.1;

 

не слушайте Борща с его принятым размером мантисы.

 

Keil использует IEEE-754:

http://www.keil.com/support/man/docs/armli...58938949149.htm

 

которого достаточно для представления 25.1, можно проверить, например, здесь:

https://www.h-schmidt.net/FloatConverter/

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ерунда, похоже, с Keil.

 

double Round (double x){

 

return x=6.1;

 

};

 

Функция возвращает 6.099998474121, как такое может, быть.

 

 

 

https://www.h-schmidt.net/FloatConverter/, проверил

6.1 это 6.099999904632568

 

похоже, так и есть

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

x = 401 * 0.0625; //25.0625

x = x * 10; //250.625

x = x + 0.5; //251.125

x = floor(x); //251

x = x / 10; // Ошибка!

А откуда числа в комментариях взялись?

Это вы вручную посчитали? А теперь попробуйте вывести результат через sprintf с форматом %e

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А откуда числа в комментариях взялись?

Это вы вручную посчитали? А теперь попробуйте вывести результат через sprintf с форматом %e

Да, вручную.

 

Уже понял, свою ошибку.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вы бы хоть немного ознакомились с тем, на что ссылаетесь (хотя бы по википедии):

Возможные конечные значения, которые могут быть представлены в формате, определяются основанием b, количеством цифр в мантиссе (с точностью р) и максимальным значением emax:

 

И лично вам в коллекцию: неявное приведение типов

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вы бы хоть немного... И лично вам...

Спасибо, конечно, но Вы бы лучше мысль свою пояснили про приведение типов. Смысл моего предложения ТС был в том, что при делении на 10 происходит приведение целого к вещественному с потерей точности, а при умножении вещественных точность выше, чем при делении. В чем я не прав? Только своими словами. Не нужно "братву с википедии" подтягивать.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В чем я не прав?
В том, что то, что вы предложили (10 ->10.0), компилятор делает сам. То есть ваше предложение эквивалентно "постучать по колесу" из известного анекдота.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

вот есть еще калькулятор который показывает и 25.1 и 25.099998 если выбирать с округлением и без округления.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

или число 25.1 невозможно представить типом float с принятым у кейла размером мантиссы. Проверьте просто x = 25.1;

число 25.1 невозмжно точно представить ни в каком варианте float, хоть double, хоть long double.

 

У Вас просто проявилась накопленная во время вычислений (всех вычислений, а не только последнего!) ошибка.

при чем тут накопленная ошибка? после выполнения floor уже все абсолютно точно.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В двоичном формате с плавающей запятой точно представимы только целые числа, либо числа дробная часть которых есть сумма (отрицательных) степеней двойки.

 

Нужно умножать дробную часть на 2 до тех пор пока она не обнулится:

0,703125 x 2 = 1,40625 | 1

0,40625 x 2 = 0,8125 | 0

0,8125 x 2 = 1,625 | 1

0,625 x 2 = 1,25 | 1

0,25 x 2 =0,5 | 0

0,5 x 2 = 1 | 1

Т. о. 0,703125 = 0,101101(2)

 

0.1 сколько на 2 не умножай, дробная часть никогда не обнулится. Т. е. в двоичном виде точно не представимо

Изменено пользователем conan

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...