Tôi nghĩ rằng các công việc sau, nhưng tôi sẽ nêu giả định của tôi đầu tiên :
- số dấu phẩy động được lưu trữ ở định dạng IEEE-754 khi bạn triển khai,
- Không tràn,
- Bạn có
nextafterf()
khả dụng (được chỉ định trong C99).
Ngoài ra, rất có thể, phương pháp này không hiệu quả lắm.
#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;
}
Trên máy tính của tôi, nó in:
Double: 0.10000000000000000555 (0x1.999999999999ap-4)
Float: 0.10000000149011611938 (0x1.99999ap-4)
tmp: 0.10000000149011611938 (0x1.99999ap-4)
converted: 0.09999999403953552246 (0x1.999998p-4)
Ý tưởng là tôi đang chuyển đổi giá trị double
đến một giá trị float
— này có thể nhỏ hơn hoặc lớn hơn giá trị gấp đôi phụ thuộc vào chế độ làm tròn. Khi được chuyển đổi trở lại double
, chúng tôi có thể kiểm tra xem nó có nhỏ hơn hoặc lớn hơn giá trị ban đầu hay không. Sau đó, nếu giá trị của float
không đúng hướng, chúng tôi xem số float
tiếp theo từ số được chuyển đổi theo hướng của số ban đầu.
Nguồn
2010-01-07 03:07:04
trên các hệ thống glibc bạn tìm thấy một ieee754.h tập tin tiêu đề, trong đó xác định các công đoàn cho các loại dấu chấm động và một cấu trúc bitfield, vì vậy bạn có thể làm việc với mantissa và số mũ dễ dàng hơn, xin lỗi nhưng tôi không thể cung cấp cho bạn thực mã. – quinmars