myślę następujące prace, ale będę podać moje założenia pierwszy :
- liczby zmiennoprzecinkowe są zapisywane w formacie IEEE-754 od implementacji,
- Brak przepełnienia,
- Masz dostępne
nextafterf()
(jest to określone w C99).
Ponadto, najprawdopodobniej ta metoda nie jest bardzo wydajna.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main(int argc, char *argv[])
{
/* Change to non-zero for superior, otherwise inferior */
int superior = 0;
/* double value to convert */
double d = 0.1;
float f;
double tmp = d;
if (argc > 1)
d = strtod(argv[1], NULL);
/* First, get an approximation of the double value */
f = d;
/* Now, convert that back to double */
tmp = f;
/* Print the numbers. %a is C99 */
printf("Double: %.20f (%a)\n", d, d);
printf("Float: %.20f (%a)\n", f, f);
printf("tmp: %.20f (%a)\n", tmp, tmp);
if (superior) {
/* If we wanted superior, and got a smaller value,
get the next value */
if (tmp < d)
f = nextafterf(f, INFINITY);
} else {
if (tmp > d)
f = nextafterf(f, -INFINITY);
}
printf("converted: %.20f (%a)\n", f, f);
return 0;
}
Na moim komputerze, drukuje:
Double: 0.10000000000000000555 (0x1.999999999999ap-4)
Float: 0.10000000149011611938 (0x1.99999ap-4)
tmp: 0.10000000149011611938 (0x1.99999ap-4)
converted: 0.09999999403953552246 (0x1.999998p-4)
Chodzi o to, że jestem przeliczania wartości double
do wartości — float
to może być mniejsza lub większa niż wartość podwójnej zależności od tryb zaokrąglania. Po przekonwertowaniu z powrotem na double
możemy sprawdzić, czy jest on mniejszy lub większy od wartości początkowej. Następnie, jeśli wartość float
nie jest we właściwym kierunku, patrzymy na następny numer float
z przekonwertowanej liczby w kierunku oryginalnego numeru.
na systemach glibc znaleźć ieee754.h pliku nagłówka, który definiuje związki dla pływających rodzajów punktowych i struktury bitfield, więc można pracować z mantysy i wykładnika łatwiejsze, przepraszam, ale nie mogę dać ci prawdziwy kod. – quinmars