Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Не работает правильно, вычисление float в Keil
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
_Алекс
Код округление числа до десятых.

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.
Понято, что происходит потеря точности.

Может есть другой способ округлить число до десятых.
psL
попробуйте поделить на 10.0
или умножить на 0.1f
Сергей Борщ
QUOTE (_Алекс @ Feb 14 2017, 07:21) *
Понято, что происходит потеря точности.
или число 25.1 невозможно представить типом float с принятым у кейла размером мантиссы. Проверьте просто x = 25.1;

не слушайте psL, он продемострировал незнание основ языка.
k155la3
Цитата(_Алекс @ Feb 14 2017, 09:21) *
Код округление числа до десятых.
. . . .
Может есть другой способ округлить число до десятых.

Решение через нетоместо, но решение.
Используйте sprintf c указанием точности, напр. %12.1f
ps
ну и исходник (s)printf можно посмотреть.
Ruslan1
Цитата(_Алекс @ Feb 14 2017, 07:21) *
При делении 251 на 10, вроде должно быть 25.1, а получается 25.0999995.

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

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

Цитата(_Алекс @ Feb 14 2017, 07:21) *
Если float поменять на double, работает.
...
Понято, что происходит потеря точности.


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

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

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

Upd: вот первое попавшееся неплохое описание вопроса. Например, интересен пункт "4.2 Неассоциативность арифметических операций", но там много и другого интересного про подводные камни плавающей точки.
psL
Цитата(Сергей Борщ @ Feb 14 2017, 09:40) *
или число 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

похоже, так и есть
HardEgor
Цитата(_Алекс @ Feb 14 2017, 12:21) *
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
_Алекс
Цитата(HardEgor @ Feb 14 2017, 13:25) *
А откуда числа в комментариях взялись?
Это вы вручную посчитали? А теперь попробуйте вывести результат через sprintf с форматом %e

Да, вручную.

Уже понял, свою ошибку.
Сергей Борщ
QUOTE (psL @ Feb 14 2017, 11:11) *
Вы бы хоть немного ознакомились с тем, на что ссылаетесь (хотя бы по википедии):
QUOTE
Возможные конечные значения, которые могут быть представлены в формате, определяются основанием b, количеством цифр в мантиссе (с точностью р) и максимальным значением emax:


И лично вам в коллекцию: неявное приведение типов
psL
Цитата(Сергей Борщ @ Feb 14 2017, 13:00) *
Вы бы хоть немного... И лично вам...

Спасибо, конечно, но Вы бы лучше мысль свою пояснили про приведение типов. Смысл моего предложения ТС был в том, что при делении на 10 происходит приведение целого к вещественному с потерей точности, а при умножении вещественных точность выше, чем при делении. В чем я не прав? Только своими словами. Не нужно "братву с википедии" подтягивать.
Сергей Борщ
QUOTE (psL @ Feb 14 2017, 14:03) *
В чем я не прав?
В том, что то, что вы предложили (10 ->10.0), компилятор делает сам. То есть ваше предложение эквивалентно "постучать по колесу" из известного анекдота.
Lagman
вот есть еще калькулятор который показывает и 25.1 и 25.099998 если выбирать с округлением и без округления.
ar__systems
Цитата(Сергей Борщ @ Feb 14 2017, 01:40) *
или число 25.1 невозможно представить типом float с принятым у кейла размером мантиссы. Проверьте просто x = 25.1;

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

Цитата(Ruslan1 @ Feb 14 2017, 03:10) *
У Вас просто проявилась накопленная во время вычислений (всех вычислений, а не только последнего!) ошибка.

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

Нужно умножать дробную часть на 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 не умножай, дробная часть никогда не обнулится. Т. е. в двоичном виде точно не представимо
ar__systems
Цитата(psL @ Feb 14 2017, 04:11) *
не слушайте Борща с его принятым размером мантисы.

Keil использует IEEE-754:
http://www.keil.com/support/man/docs/armli...58938949149.htm

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

Вы просто не понимаете, как работает представление чисел с плавающей точкой. 25.1 не представляются точно в двойчной системе.

Чтобы было (я надеюсь) понятно, ответьте на простой вопрос - сколько надо ДЕСЯТИЧНЫХ разрядов чтобы ТОЧНО представить число 1/3? Теперь понятно? 251/10 в двоичной системе это абсолютно такая же ситуация.

Conan, cheers.gif

Цитата(psL @ Feb 14 2017, 07:03) *
Спасибо, конечно, но Вы бы лучше мысль свою пояснили про приведение типов. Смысл моего предложения ТС был в том, что при делении на 10 происходит приведение целого к вещественному с потерей точности, а при умножении вещественных точность выше, чем при делении. В чем я не прав? Только своими словами. Не нужно "братву с википедии" подтягивать.

Ерунда. Приведение ЦЕЛОГО к вещественному происходит без потери точности.
Поделить на 10 и умножить на 0.1 дадут одинаковый результат, хотя теоретически делить даже лучше, потому что в этом случае оба аргумента представлены абсолютно точно, в отличии от 0.1.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2024 Invision Power Services, Inc.