наименьший поплавок, который можно суммировать с другим поплавком

Предполагая, что есть число с плавающей запятой с 7 цифрами, как найти наименьшее число, которое можно добавить к этому числу с плавающей запятой?

Пример 1: 1234,567f + 0000,001f = 1234,568f

Пример 2: 0,01234567 + 0,00000001f = 0,01234568f


person MathiasDG    schedule 22.10.2015    source источник
comment
В C (или C++) вы должны вызвать nextafter и вычесть. К сожалению, для этой полезной операции нет оболочки .NET.   -  person Ben Voigt    schedule 22.10.2015
comment
Дубликат stackoverflow.com/questions/9485943/   -  person Pascal Cuoq    schedule 23.10.2015


Ответы (2)


ОП добавил C# после публикации этого C ответа.

Оставлю это решение C в качестве эталона.


Распечатайте число в экспоненциальном формате и измените каждую цифру на «0» или «1».

float smallest_float_summable(float f, int digs) {
  char buf[20];

  sprintf(buf, "%.*e", digs - 1, f);
  char *p = buf;
  while (*p != 'e') {
    if (isdigit(*p)) {
      *p = '0' + (p[1] == 'e');
    }
    p++;
  }
  float y;
  sscanf(buf, "%e", &y);
  return y;
}

 printf("%e\n", smallest_float_summable(1234.567f, 7));
 // 1.000000e-03

Это не приведет к наименьшему, поскольку обычно число около 1/2 значения smallest_float_summable() будет влиять на изменение, но, похоже, это соответствует намерению OP.


Чтобы получить наименьшее число, которое повлияет на некоторые изменения, просто используйте nextafter()

Функции nextafter определяют следующее представляемое значение в типе функции после x в направлении y ... C11dr §7.12.11.3 2

#include <math.h>
float smallest_change(float f) {
  float dif = f - nextafterf(f, 0);
  return dif;
}

[Редактировать]

@aka.nice правильно указывает, что даже меньше, может быть, около 1/2 dif произведет изменение. Будет обдумывать это.

person chux - Reinstate Monica    schedule 22.10.2015
comment
Но, предполагая режим округления по умолчанию IEEE 754, вы могли бы получить еще меньшее число dif, если значащая f нечетна, нет? dif тогда будет 1/2 ulp - person aka.nice; 22.10.2015
comment
@aka.nice Хорошее замечание. Потребуется некоторая мысль, чтобы покрыть угловые случаи, как вы предложили. - person chux - Reinstate Monica; 22.10.2015

Чтобы найти наименьший эпсилон, вы можете начать с 10eN, где N равно 1, перейти к меньшему числу и добавить его. Затем сравните его с исходным числом.

number = x

N = 1
newnumber = 3
while (number <> newnumber){
  newnumber = (number + 10eN)
  N = N - 1
}

Then 10e(N+1) is the smallest epsilon.
person ergonaut    schedule 22.10.2015
comment
Если бы number было большим, как 1e30, то N нужно было бы начинать с большего значения, например 24 или больше, а не с 1. - person chux - Reinstate Monica; 22.10.2015