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

 
 
2 страниц V   1 2 >  
Reply to this topicStart new topic
> Как правильно выполнять округление до ближайшего?, RealView Compiler
sonycman
сообщение Dec 13 2009, 23:19
Сообщение #1


Любитель
*****

Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695



Заметил, что при приведении типа с плав. точкой (float) к целочисленному значению, дробная часть просто выкидывается, или производится округление к нулю: было 4.8, стало -> 4.
А надо бы юзать округление до ближайшего целого -> 5.

Пришлось подключить хидер rt_fp.h и пользоваться тамошней функцией UINT _ffixu_r(float).

Может быть, режим округления можно изменить каким-то другим, более правильным путём, не прибегая к вызову функций внешней библиотеки?

И почему такой грубый способ округления юзается по умолчанию? Разве это правильно - 4.8 округлять до 4? cranky.gif
Go to the top of the page
 
+Quote Post
rezident
сообщение Dec 13 2009, 23:26
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Приведение типа переменной и округление чисел, вообще говоря не очень связанные между собой операции. Самый простой способ общепринятого округления чисел при преобразовании из float в int это прибавление к результату 0.5f непосредственно перед таким преобразованием.
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Dec 13 2009, 23:52
Сообщение #3


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Цитата(rezident @ Dec 14 2009, 02:26) *
Самый простой способ общепринятого округления чисел при преобразовании из float в int это прибавление к результату 0.5f непосредственно перед таким преобразованием.

Только числа бывают и отрицательными.

ИМХО, лучше вариант (int)floor(x + 0.5)
Go to the top of the page
 
+Quote Post
rezident
сообщение Dec 14 2009, 00:43
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Цитата(aaarrr @ Dec 14 2009, 04:52) *
Только числа бывают и отрицательными.
Согласен. У меня предложено "округление к большему". Если нужно именно "округление к ближайшему целому", то нужно учитывать знак числа.
Go to the top of the page
 
+Quote Post
Microwatt
сообщение Dec 14 2009, 01:22
Сообщение #5


Гуру
******

Группа: Почетный участник
Сообщений: 6 851
Регистрация: 25-08-08
Из: Запорожье
Пользователь №: 39 802



да, один клерк в банке наокруглял десятые доли цента за пять лет что-то на 20000 баксов.
И судить было вроде не за что, раньше машина их просто отбрасывала, а он заставил переводить на свой счет.
Go to the top of the page
 
+Quote Post
dch
сообщение Dec 14 2009, 02:00
Сообщение #6


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

Группа: Участник
Сообщений: 1 179
Регистрация: 15-09-04
Из: 141070 г. Королев МО, улица Горького 39-121
Пользователь №: 661



Цитата(sonycman @ Dec 14 2009, 02:19) *
Разве это правильно - 4.8 округлять до 4?

это такое соглашение если в выражении языка C нет вещественных то арифметика целочисленная
1/3 дает в результате 0, а если есть вещественное, то каждое целое переводится в вещественное 1/3. дает около одной трети :-)
Go to the top of the page
 
+Quote Post
sonycman
сообщение Dec 14 2009, 09:23
Сообщение #7


Любитель
*****

Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695



Цитата(rezident @ Dec 14 2009, 03:26) *
Приведение типа переменной и округление чисел, вообще говоря не очень связанные между собой операции. Самый простой способ общепринятого округления чисел при преобразовании из float в int это прибавление к результату 0.5f непосредственно перед таким преобразованием.

Вот, спасибо, теперь буду знать smile.gif
Хотя и смахивает это на некий костыль...

Цитата(aaarrr @ Dec 14 2009, 03:52) *
Только числа бывают и отрицательными.
ИМХО, лучше вариант (int)floor(x + 0.5)

А вот здесь не понял, floor при округлении отрицательного числа (-4.8 + 0.5 = -4.3) даст результат -5?
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Dec 14 2009, 09:44
Сообщение #8


неотягощённый злом
******

Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643



Цитата(sonycman @ Dec 14 2009, 12:23) *
А вот здесь не понял, floor при округлении отрицательного числа (-4.8 + 0.5 = -4.3) даст результат -5?
Судя по всему да. ссылка
А я использую вот такие макросы
Код
#define FROUND(x)                 ((unsigned long)((x)+0.5f))
#define FROUNDS(x)                (((x)>=0)?(long)((x)+0.5f):(long)((x)-0.5f))

До такого не додумалсяsmile.gif
Цитата(aaarrr @ Dec 14 2009, 02:52) *
ИМХО, лучше вариант (int)floor(x + 0.5)


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
sonycman
сообщение Dec 14 2009, 09:53
Сообщение #9


Любитель
*****

Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695



demiurg_spb
По идее да - floor округляет до целого, не превышающего начальное значение.
Если округлить -4.8 до -4, то -4 будет больше -4.8.
Значит, правильно будет -5 smile.gif

В принципе, чтобы юзать floor, надо подключить math.h
А чтобы юзать _ffixu_r, которая округлит число безо всяких заморочек, надо подключить rt_fp.h.
Не знаю, есть ли между ними какая-то разница smile.gif

Имхо - самое простое - юзать предложенные вами макросы smile.gif
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Dec 14 2009, 10:54
Сообщение #10


неотягощённый злом
******

Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643



Цитата(sonycman @ Dec 14 2009, 12:53) *
В принципе, чтобы юзать floor, надо подключить math.h
Это не страшно.
Цитата
А чтобы юзать _ffixu_r, которая округлит число безо всяких заморочек, надо подключить rt_fp.h.
А это уже нестандартно (видимо от keil примочки).
Цитата
Имхо - самое простое - юзать предложенные вами макросы smile.gif
Это как сказать... У меня два макроса, а ведь можно обойтись одним. Вопрос что оптимальнее. Нужно экспериментировать.


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
tag
сообщение Dec 14 2009, 11:24
Сообщение #11


Частый гость
**

Группа: Свой
Сообщений: 151
Регистрация: 21-02-06
Пользователь №: 14 561



Цитата(sonycman @ Dec 14 2009, 02:19) *
Заметил, что при приведении типа с плав. точкой (float) к целочисленному значению, дробная часть просто выкидывается, или производится округление к нулю: было 4.8, стало -> 4.


В описании языка C четко сказано, что при приведении типа от вещественного к целочисленному дробная часть просто отсекается.
Go to the top of the page
 
+Quote Post
sonycman
сообщение Dec 14 2009, 11:44
Сообщение #12


Любитель
*****

Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695



Цитата(tag @ Dec 14 2009, 15:24) *
В описании языка C четко сказано, что при приведении типа от вещественного к целочисленному дробная часть просто отсекается.

Я в курсе.
Имхо - очередная бяка стандарта sad.gif
Почему то, в тех редких случаях, когда приходится юзать плавучку, ни разу не приходила в голову мысль портить вычисления использованием столь грубого округления.
Всегда приходится обходить "чётко оговоренный" стандарт sad.gif
Go to the top of the page
 
+Quote Post
baralgin
сообщение Dec 14 2009, 13:16
Сообщение #13


Частый гость
**

Группа: Участник
Сообщений: 92
Регистрация: 23-12-08
Из: Кишинёв
Пользователь №: 42 680



sonycman Операция отбрасывания дробной части лёгкая для процессора(наличие fpu роли не играет), в отличии от полноценного округления. Округление нужно далеко не всегда, поэтому можно избежать использования лишних операций. Так наверное во всех вменяемых языках устроено...
Цитата(sonycman @ Dec 14 2009, 13:44) *
Почему то, в тех редких случаях, когда приходится юзать плавучку, ни разу не приходила в голову мысль портить вычисления использованием столь грубого округления.

Ммм.. а например при целочисленном делении ( a / b, a >> x) вам никогда не приходило в голову, что значения напрасно портяться? smile.gif (хотя могут быть относительно легко "округлены").
Go to the top of the page
 
+Quote Post
sonycman
сообщение Dec 14 2009, 15:39
Сообщение #14


Любитель
*****

Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695



Цитата(baralgin @ Dec 14 2009, 17:16) *
Ммм.. а например при целочисленном делении ( a / b, a >> x) вам никогда не приходило в голову, что значения напрасно портяться? smile.gif (хотя могут быть относительно легко "округлены").

Не понял, в каком месте при делении "портятся значения"? Нужен остаток - никто не мешает его сохранить и использовать в вычислениях дальше.

А вот при отбрасывании дробной части числа 4.99 мы получаем чувствительную ошибку.
Я не затем проводил рассчёт в плавучке, чтобы затем при банальной передаче параметров всё угробить smile.gif
Go to the top of the page
 
+Quote Post
Sneg_87
сообщение Dec 14 2009, 16:22
Сообщение #15


Участник
*

Группа: Участник
Сообщений: 41
Регистрация: 12-10-09
Пользователь №: 52 882



предлагаю такой вариант:

long a=5.6;
//перед преобразованием умножать на 10, чтоб был остаток от деления в дальнейшем
a=a*10;
//теперь а=56
a=((int)(a+a%10))/10;
//поясню (int) (56+6) и деленое на 10 будет 6, что и необходимо

для отрицательного числа тоже пойдет


ЗЫ при проверке в досовском Borland: задавал а=5.1 далее умножал на 10 и получал а=50.999. кто может объяснить в чем дело?


--------------------
coding, кодинг, koDinГ, copyriting, printing ....
Go to the top of the page
 
+Quote Post

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

 


RSS Текстовая версия Сейчас: 19th July 2025 - 00:34
Рейтинг@Mail.ru


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