Arrondi en virgule flottante

13

Un nombre à virgule flottante IEEE-754 <1 (c'est-à-dire généré avec un générateur de nombres aléatoires qui génère un nombre> = 0,0 et <1,0) peut-il être multiplié par un entier (sous forme de virgule flottante) pour obtenir un nombre égal ou supérieur à cet entier en raison de l'arrondi?

c'est à dire

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

Cela pourrait être équivalent à dire qu'il existe un N et R tels que si R est le plus grand nombre inférieur à 1 qui peut être représenté dans IEEE-754 alors N * R> = N (où * et> = sont appropriés IEEE- 754 opérateurs)

Cela vient de cette question basée sur cette documentation et la fonction aléatoire postgresql

Cade Roux
la source
Pouvez-vous dire quelque chose sur la plage de N, c'est-à-dire qu'elle est suffisamment petite pour être représentée exactement dans la double précision IEEE-754?
Pedro
@Pedro Dans ce cas particulier, oui, ce serait un petit entier - c'est-à-dire 10. Je suppose que vous dites que si N est un très grand entier avec un très grand nombre de chiffres significatifs, il pourrait ne pas être représenté exactement?
Cade Roux
Exactement, si , alors peut être plus grand que . f l ( R × f l ( N ) ) R Nfl(N)>Nfl(R×fl(N))RN
Pedro

Réponses:

8

En supposant arrondir au plus proche et que , alors toujours. (Veillez à ne pas convertir un entier trop grand.)N R < NN>0NR<N

Soit , où est la signification et est l'exposant entier. Soit et dériver la bornec [ 1 , 2 ) q 1 - 2 - s = Rc2q=Nc[1,2)q12s=R

NR=c2q(12s)c2q2qs,

avec égalité si et seulement si . Le côté droit est inférieur à et, puisque est exactement unité à la dernière place de , soit et est exactement représentable (puisque est normal et non la plus petite normale), ou , et l'arrondi le plus proche est vers le bas. Dans les deux cas, est inférieur à .c=1N2qs0.5Nc=12q2qsNc>1NRN


L'arrondi à la hausse peut poser un problème, non qu'il doive jamais être sélectionné en présence d'utilisateurs sans méfiance. Voici du C99 qui imprime "0\n1\n"sur ma machine.

#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));
}
Tyrone
la source
Je suis désolé, je suis un peu lent ces jours-ci - j'ai du mal à obtenir la part de l'inégalité
c2q2s2qs
Cade Roux
@Cade Apparemment, je ne peux pas faire d'algèbre aujourd'hui. Je voulais dire . 2qs
Tyrone
Merci, je ne savais pas s'il y avait une autre étape qui me manquait.
Cade Roux