Apakah ada cara untuk secara terprogram mendapatkan penggandaan yang paling dekat dengan 1.0, tetapi sebenarnya bukan 1.0?
Salah satu cara hacky untuk melakukan ini adalah dengan memcpy double menjadi integer berukuran sama, lalu kurangi satu. Cara kerja format floating-point IEEE754, ini akan berakhir dengan penurunan eksponen satu kali saat mengubah bagian pecahan dari semua nol (1,000000000000) menjadi semua satu (1,111111111111). Namun ada mesin di mana bilangan bulat disimpan little-endian sementara floating-point disimpan big-endian, jadi itu tidak akan selalu berfungsi.
c++
floating-point
floating-accuracy
jorgbrown
sumber
sumber
nextafter()
adalah satu-satunya cara yang tepat untuk mencapai apa yang dia inginkan.1.0000...
biner adalah penurunan ke0.111111....
dan untuk menormalkannya, Anda harus menggesernya ke kiri:1.11111...
yang mengharuskan Anda menurunkan eksponen. Dan kemudian Anda berjarak 2 ulp dari 1.0. Jadi tidak, mengurangi satu dari nilai integral TIDAK memberi Anda apa yang ditanyakan di sini.Jawaban:
Di C dan C ++, berikut ini memberikan nilai yang paling dekat dengan 1.0:
#include <limits.h> double closest_to_1 = 1.0 - DBL_EPSILON/FLT_RADIX;
Namun perlu diperhatikan bahwa dalam versi C ++,
limits.h
tidak digunakan lagi dan digantikanclimits
. Namun, jika Anda tetap menggunakan kode khusus C ++, Anda dapat menggunakan#include <limits> typedef std::numeric_limits<double> lim_dbl; double closest_to_1 = 1.0 - lim_dbl::epsilon()/lim_dbl::radix;
Dan seperti yang Jarod42 tulis dalam jawabannya, karena C99 atau C ++ 11 Anda juga dapat menggunakan
nextafter
:#include <math.h> double closest_to_1 = nextafter(1.0, 0.0);
Tentu saja di C ++ Anda dapat (dan untuk versi C ++ yang lebih baru harus) menyertakan
cmath
dan menggunakanstd::nextafter
sebagai gantinya.sumber
Sejak C ++ 11, Anda dapat menggunakan
nextafter
untuk mendapatkan nilai yang dapat direpresentasikan berikutnya dalam arah tertentu:std::nextafter(1., 0.); // 0.99999999999999989 std::nextafter(1., 2.); // 1.0000000000000002
Demo
sumber
std::ceil(std::nextafter(1., std::numeric_limits<double>::max()))
.nextafter
, dan beginilah cara musl mengimplementasikannya jika ada orang lain yang ingin melihat cara melakukannya. Pada dasarnya: memutar-mutar bit mentah.Di C, Anda dapat menggunakan ini:
#include <float.h> ... double value = 1.0+DBL_EPSILON;
DBL_EPSILON
adalah perbedaan antara 1 dan nilai terkecil lebih besar dari 1 yang dapat direpresentasikan.Anda harus mencetaknya menjadi beberapa digit untuk melihat nilai sebenarnya.
Di platform saya,
printf("%.16lf",1.0+DBL_EPSILON)
berikan1.0000000000000002
.sumber
1.
sebagai1'000'000
Demo1.0
. BTW, ini juga memberikan nilai terdekat lebih besar dari 1, dan bukan nilai terdekat absolut ke 1 (yang mungkin lebih kecil dari 1). Jadi saya setuju bahwa ini adalah jawaban parsial, tetapi saya pikir itu tetap bisa berkontribusi.Di C ++ Anda juga bisa menggunakan ini
1 + std::numeric_limits<double>::epsilon()
sumber