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


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>0N∗R<N

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

NR=c2−q(1−2−s)≤c2−q−2−q−s,

с равенством тогда и только тогда, когда . Правая часть меньше и, поскольку - это точно единицы в последнем месте , либо и является точно представимым (поскольку является нормальным, а не наименьшим нормальным), или , а ближайшее округление направлено вниз. В обоих случаях, меньше , чем .c=1N2−q−s0.5Nc=12−q−2−q−sNc>1N∗RN


Округление вверх может вызвать проблему, а не то, что его следует выбирать в присутствии ничего не подозревающих пользователей. Вот какой-то С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));
}

Извините, я немного медлительный в эти дни - у меня проблемы с получением части неравенства
−c2−q2−s≤−2−qs
— Кейд Ру

@Cade Очевидно, я не умею сегодня заниматься алгеброй. Я имел в виду . 2−q−s
— Тайрон

Спасибо, я не был уверен, был ли еще один шаг, который я пропустил.
— Cade Roux
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.