Округление с точностью до заданного числа

Seva1800
Offline
Зарегистрирован: 18.12.2015
 
Господа. Понадобилось округлять значение переменной (float) c точностью до 0.0005.
Сделал как показано ниже. Работает.

 //__________________________Округление Upr (float) с точностью до 0,0005
  S = round (Upr * 10000); // Пример 1,925619*10000 = 19256,19 => S=19256
  byte t = S % 10; // t=6
  if (t < 3) {
    t = 0;
  }
  if (t > 7) {
    t = 10;
  }
  if (t >= 3 && t <= 7) {
    t = 5;
  }
  S = S / 10 * 10 + t; // t=5, S= 19250 + 5
  Upr = S / 10000.0; // Upr  = 1.9255

Однако, теперь понадобилось округление с точностью до 0,0002.

Подскажите пожалуйста более гуманный способ округления. Может быть есть покороче алгоритмы?

 

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

long  SS=(float)UPR*5000;

float S=SS/5000;

И все лишнее отпадет.

Seva1800
Offline
Зарегистрирован: 18.12.2015

Строка 05 это делает. У меня задача не убрать лишнее - это не проблема, а округлить до заданной точности.

Если точность 0.0005, то число 1,925619 превращается, очевидно, в 1.9255.

А надо еще до 0.0002 округлять, т.е. то же число 1,925619 должно преобразоваться в 1.9256, а число 1.92571 должно округиться до 1.9258.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Ну так добавляете половину младшего разряда:

long  SS=(float)UPR*5000 + 0.5;

Seva1800
Offline
Зарегистрирован: 18.12.2015

И что? Опять отбрасывание. Причем еще и ошибаться будет. А округление-то с точностью до заданного числа где?

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Seva1800 пишет:

И что? Опять отбрасывание. Причем еще и ошибаться будет. А округление-то с точностью до заданного числа где?

Учите математику. Без знания математики в программировании сложно. А раскладывать вам математическое доказательство. Ну-ну. Ищите идиота в другом месте.

Datak
Offline
Зарегистрирован: 09.10.2014






   float S;
   float Upr;
   .....
 
   S = round(Upr * 2000) / 2000; // округление c точностью до 0.0005
   S = round(Upr * 5000) / 5000; // округление c точностью до 0.0002

Примерно так, если чисто по логике.

Но на самом деле, всё не так просто. Мы пытаемся округлить до десятичных знаков, но на самом деле float-числа хранятся в двоичном виде. То есть, после нашего округления они будут округлены ещё раз - до ближайшего двоичного значения. Это значит, потом, при выводе в десятичном виде, опять могут появиться лишние знаки.

Не знаю, понятно ли написал - но в общем, такое округление правильно работает на не слишком больших числах, и не слишком маленьких. Как и алгоритм из стартового поста, насколько я понимаю.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Datak, спасибо, что напомнили об особенностях вещественных чисел, но другого округления все равно нет, так что приходится мириться со всеми недостатками и несовершенствами.

ssss
Offline
Зарегистрирован: 01.07.2016

Datak пишет:
такое округление правильно работает на не слишком больших числах, и не слишком маленьких. Как и алгоритм из стартового поста, насколько я понимаю.

Вы путаете округление и формат данных. А это разные вещи.

Seva1800
Offline
Зарегистрирован: 18.12.2015

Вероятно я неправильно задал тему. Прошу прощения. Мне нужно получить в заданном разряде после запятой так сказать определенную дискретность. Т.е число в заданном разяре должно быть кратным заданному.

Поясню на простом примере (точность 0.5) c меньшим кол-вом цифр:

Входящее число (float)           число на выходе

1.0                                                1.0

1.1                                                1.0

1.2                                                1.0

1.3                                                1.5

1.4                                                1.5

1.5                                                1.5

1.6                                                1.5

1.7                                                1.5

1.8                                                2.0

1.9                                                2.0

2.0                                                2.0

Кусок кода в начальном сообщении прекрасно справляется с этой задачей без ошибок.

Однако, как я писал теперь нужно сделать младший заданный разряд кратным 2-ке, а конкретно 0.0002.

Можно решить задачу так же как я сделал для пятерки, анализируя младший заданный разряд числа.

Однако может быть как-то можно покороче? Чтобы не плодить if.

 

 

 

Datak
Offline
Зарегистрирован: 09.10.2014

ssss пишет:

Datak пишет:
такое округление правильно работает на не слишком больших числах, и не слишком маленьких. Как и алгоритм из стартового поста, насколько я понимаю.

Вы путаете округление и формат данных. А это разные вещи.

Я не путаю вещи, я просто путаюсь в показаниях. :)
То есть, не умею достаточно чётко объяснять, о чём и предупреждал.

Да, строго говоря, ошибка из-за перевода между двоичной/десятичной системами, и ошибка из-за ограниченного размера мантиссы float-числа - это разные вещи, и они обе вносят погрешность в конечный результат.

И, раз уж зашёл, поправлю самого себя. "Слишком большие" и "слишком маленькие" - это не совсем правильно. Тут важно не значение, а именно точность числа - то есть, количество значащих цифр - не важно, до запятой или после.

nik182
Offline
Зарегистрирован: 04.05.2015
round(x[i]*500)/500
x          получилось
0.0013 0.002
0.0023 0.002
0.0033 0.004
0.0043 0.004
0.0053 0.006
0.0063 0.006
0.0073 0.008
0.0083 0.008