Округление с плавающей точкой

13

Может ли число с плавающей запятой IEEE-754 <1 (т. Е. Созданное с помощью генератора случайных чисел, который генерирует число> = 0,0 и <1,0) когда-либо умножаться на некоторое целое число (в форме с плавающей запятой), чтобы получить число, равное или большее, чем что целое число из-за округления?

т.е.

double r = random() ; // generates a floating point number in [0, 1)
double n = some_int ;
if (n * r >= n) {
    print 'Rounding Happened' ;
}

Это может быть эквивалентно утверждению, что существуют N и R, такие, что если R является наибольшим числом, меньшим 1, которое может быть представлено в IEEE-754, то N * R> = N (где * и> = являются подходящими IEEE- 754 оператора)

Это вытекает из этого вопроса, основанного на этой документации и случайной функции postgresql

Кейд Ру
источник
Можете ли вы сказать что-нибудь о диапазоне N, то есть достаточно ли он мал, чтобы быть точно представленным в двойной точности IEEE-754?
Педро
@Pedro В данном конкретном случае, да, это было бы маленькое целое число - то есть 10. Я предполагаю, что вы говорите, что если N - очень большое целое число с очень большим количеством значащих цифр, оно может быть не в состоянии быть точно представленным?
Cade Roux
Точно, если , то может быть больше, чем . fl(N)>NR Nfl(R×fl(N))RN
Педро

Ответы:

8

Предполагая округление до ближайшего и что , тогда всегда. (Будьте осторожны, чтобы не преобразовать слишком большое целое число.)N R < NN>0NR<N

Пусть , где - значение, а - целое число. Пусть и получим оценкуc [ 1 , 2 ) q 1 - 2 - s = Rc2q=Nc[1,2)q12s=R

NR=c2q(12s)c2q2qs,

с равенством тогда и только тогда, когда . Правая часть меньше и, поскольку - это точно единицы в последнем месте , либо и является точно представимым (поскольку является нормальным, а не наименьшим нормальным), или , а ближайшее округление направлено вниз. В обоих случаях, меньше , чем .c=1N2qs0.5Nc=12q2qsNc>1NRN


Округление вверх может вызвать проблему, а не то, что его следует выбирать в присутствии ничего не подозревающих пользователей. Вот какой-то С99, который печатает "0\n1\n"на моей машине.

#include <fenv.h>
#include <math.h>
#include <stdio.h>

int main(void) {
    double n = 10;
    double r = nextafter(1, 0);
    printf("%d\n", n == (n * r));
    fesetround(FE_UPWARD);
    printf("%d\n", n == (n * r));
}
Тайрон
источник
Извините, я немного медлительный в эти дни - у меня проблемы с получением части неравенства
c2q2s2qs
Кейд Ру
@Cade Очевидно, я не умею сегодня заниматься алгеброй. Я имел в виду . 2qs
Тайрон
Спасибо, я не был уверен, был ли еще один шаг, который я пропустил.
Cade Roux