Pertanyaan Cross platform / compiler konsisten sprintf dari angka floating point


Kami memiliki permainan yang perlu bersifat deterministik karena merupakan bagian dari model multipemainnya. Kami juga menggunakan Lua, yang menggunakan sprintf secara internal (formatnya adalah %.14g).

Masalah muncul ketika mencetak angka seperti 0,00001. Dalam beberapa kasus mencetak 1e-05 dan dalam beberapa kasus lain, ia mencetak 1e-005 (ekstra nol).

Misalnya ketika dikompilasi dengan Visual Studio 2015 yang dicetaknya 1e-005, dan dengan Visual studio 2013 yang dicetaknya 1e-05. Saya mencoba pengaturan lokal yang berbeda, tetapi tampaknya tidak memiliki efek apa pun.

Pertanyaannya adalah: Apa solusi terbaik untuk mencapai hasil deterministik? Saya tidak terlalu peduli jika notasi ilmiah distandardisasi, atau dihilangkan.

Solusi yang saya pikirkan:

  • Saat saya menggunakan %f notasi, tidak mengabaikan angka nol yang tidak signifikan, sehingga memiliki %.14f akan menghasilkan bilangan panjang yang tidak praktis.
  • Menggunakan custom sprintf metode (salin yang disalin dari beberapa pustaka standar)
  • Menggunakan beberapa format khusus yang tidak saya pikirkan (saya hanya menggunakan ini sebagai referensi: http://www.cplusplus.com/reference/cstdio/printf/)

32
2017-10-16 14:55


asal


Jawaban:


Anda dapat beralih ke LuaJIT. Ini memformat angka secara konsisten di antara platform.

Dari halaman ekstensi:

tostring () dll. mengkanonisisasi NaN dan ± Inf

Semua konversi angka-ke-string secara konsisten mengkonversi nomor non-terbatas ke string yang sama di semua platform. Hasil NaN dalam "nan", infinity positif menghasilkan "inf" dan hasil tak terbatas negatif dalam "-inf".

tonumber () dll. menggunakan string bawaan untuk konversi angka

Semua konversi string-ke-angka secara konsisten mengkonversi integer dan input titik-mengambang dalam desimal dan heksadesimal pada semua platform. strtod () tidak digunakan lagi, yang menghindari banyak masalah dengan implementasi perpustakaan C yang buruk. Fungsi konversi bawaan menyediakan presisi penuh sesuai dengan standar IEEE-754, ia bekerja secara independen dari lokal saat ini dan mendukung angka floating-point hex (misalnya 0x1.5p-3).


18
2017-10-16 17:44



Jawaban yang paling banyak dipilih salah, karena dokumentasi salah di tempat pertama.

Inilah yang terjadi di LuaJIT:

#define lua_number2str(s,n)sprintf((s),"%.14g",(n))
#define lua_str2number(s,p)strtod((s),(p))

Melihat ke tonumber dan tostring implementasi itu adalah makro yang dipanggil untuk mendapatkan hasilnya.

Jangan ragu untuk mengoreksi jawaban ini jika Anda menemukan implementasi "bawaan" yang sebenarnya, karena saya penasaran juga untuk mengetahui cara kerjanya.


4
2017-09-13 11:43



Setahun kemudian, inilah cara kami memecahkannya.

Kami mengunduh implementasi cetak kustom (trio) dan penggunaan paksa dari implementasi ini daripada sistem yang ada di lua (dan sumber kami).

Kami juga harus berubah

long double trio_long_double_t;

untuk

double trio_long_double_t;

di triodef.h untuk memastikan Visual Studio dan linux / mac memberikan hasil yang sama.


3
2017-10-04 12:53



Lua memberi Anda math.frexp di pustaka standar. Anda dapat menggunakan ini untuk memisahkan pelampung Anda menjadi bentuk eksponen dan mantissa, dan kemudian melakukan cetakan khusus dalam Lua murni yang tidak akan bergantung pada platform yang mendasarinya. Berikut ini contohnya:

m,e = math.frexp(val)
io.write(m)
io.write('E')
io.write(e)

PS Menikmati Fakta Jum'at, teruskan mereka datang :)


1
2018-05-15 13:13