реклама на сайте
подробности

 
 
2 страниц V   1 2 >  
Reply to this topicStart new topic
> Не работает правильно, вычисление float в Keil, Деление на 10
_Алекс
сообщение Feb 14 2017, 05:21
Сообщение #1


Местный
***

Группа: Свой
Сообщений: 252
Регистрация: 14-09-06
Пользователь №: 20 377



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

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

Может есть другой способ округлить число до десятых.
Go to the top of the page
 
+Quote Post
psL
сообщение Feb 14 2017, 05:48
Сообщение #2


Знающий
****

Группа: Свой
Сообщений: 526
Регистрация: 5-08-05
Пользователь №: 7 390



попробуйте поделить на 10.0
или умножить на 0.1f

Сообщение отредактировал Herz - Feb 14 2017, 08:33
Причина редактирования: Избыточное цитирование
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Feb 14 2017, 06:40
Сообщение #3


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



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

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


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
k155la3
сообщение Feb 14 2017, 06:49
Сообщение #4


Профессионал
*****

Группа: Свой
Сообщений: 1 123
Регистрация: 8-03-09
Из: Днепр
Пользователь №: 45 848



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

Решение через нетоместо, но решение.
Используйте sprintf c указанием точности, напр. %12.1f
ps
ну и исходник (s)printf можно посмотреть.


Сообщение отредактировал k155la3 - Feb 14 2017, 06:52
Go to the top of the page
 
+Quote Post
Ruslan1
сообщение Feb 14 2017, 08:10
Сообщение #5


Гуру
******

Группа: Свой
Сообщений: 2 360
Регистрация: 6-03-06
Из: Кишинев
Пользователь №: 15 025



Цитата(_Алекс @ 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 Неассоциативность арифметических операций", но там много и другого интересного про подводные камни плавающей точки.
Go to the top of the page
 
+Quote Post
psL
сообщение Feb 14 2017, 09:11
Сообщение #6


Знающий
****

Группа: Свой
Сообщений: 526
Регистрация: 5-08-05
Пользователь №: 7 390



Цитата(Сергей Борщ @ 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/
Go to the top of the page
 
+Quote Post
_Алекс
сообщение Feb 14 2017, 09:17
Сообщение #7


Местный
***

Группа: Свой
Сообщений: 252
Регистрация: 14-09-06
Пользователь №: 20 377



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

double Round (double x){

return x=6.1;

};

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



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

похоже, так и есть
Go to the top of the page
 
+Quote Post
HardEgor
сообщение Feb 14 2017, 09:25
Сообщение #8


Гуру
******

Группа: Свой
Сообщений: 2 223
Регистрация: 3-03-06
Из: Tomsk
Пользователь №: 14 925



Цитата(_Алекс @ 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
Go to the top of the page
 
+Quote Post
_Алекс
сообщение Feb 14 2017, 09:32
Сообщение #9


Местный
***

Группа: Свой
Сообщений: 252
Регистрация: 14-09-06
Пользователь №: 20 377



Цитата(HardEgor @ Feb 14 2017, 13:25) *
А откуда числа в комментариях взялись?
Это вы вручную посчитали? А теперь попробуйте вывести результат через sprintf с форматом %e

Да, вручную.

Уже понял, свою ошибку.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Feb 14 2017, 10:00
Сообщение #10


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



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


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


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
psL
сообщение Feb 14 2017, 12:03
Сообщение #11


Знающий
****

Группа: Свой
Сообщений: 526
Регистрация: 5-08-05
Пользователь №: 7 390



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

Спасибо, конечно, но Вы бы лучше мысль свою пояснили про приведение типов. Смысл моего предложения ТС был в том, что при делении на 10 происходит приведение целого к вещественному с потерей точности, а при умножении вещественных точность выше, чем при делении. В чем я не прав? Только своими словами. Не нужно "братву с википедии" подтягивать.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Feb 14 2017, 14:19
Сообщение #12


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



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


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
Lagman
сообщение Feb 14 2017, 15:14
Сообщение #13


Знающий
****

Группа: Свой
Сообщений: 875
Регистрация: 28-10-05
Пользователь №: 10 245



вот есть еще калькулятор который показывает и 25.1 и 25.099998 если выбирать с округлением и без округления.
Go to the top of the page
 
+Quote Post
ar__systems
сообщение Feb 14 2017, 16:06
Сообщение #14


self made
****

Группа: Свой
Сообщений: 855
Регистрация: 7-03-09
Из: Toronto, Canada
Пользователь №: 45 795



Цитата(Сергей Борщ @ Feb 14 2017, 01:40) *
или число 25.1 невозможно представить типом float с принятым у кейла размером мантиссы. Проверьте просто x = 25.1;

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

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

при чем тут накопленная ошибка? после выполнения floor уже все абсолютно точно.
Go to the top of the page
 
+Quote Post
conan
сообщение Feb 14 2017, 16:10
Сообщение #15


Участник
*

Группа: Участник
Сообщений: 56
Регистрация: 3-11-11
Пользователь №: 68 126



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

Нужно умножать дробную часть на 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 - Feb 14 2017, 16:11
Go to the top of the page
 
+Quote Post

2 страниц V   1 2 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 20th June 2025 - 07:27
Рейтинг@Mail.ru


Страница сгенерированна за 0.01474 секунд с 7
ELECTRONIX ©2004-2016