Định dạng số dấu phẩy động chính xác là số thập phân


9

Bất kỳ dấu phẩy động nhị phân có thể được định dạng chính xác trong thập phân. Chuỗi kết quả có thể hơi dài, nhưng nó có thể. Trong bài viết của tôi về điểm nổi tôi đề cập đến tầm quan trọng của độ chính xác, và bây giờ tôi muốn chức năng này. Thách thức này là viết một chương trình hoặc hàm, lấy một giá trị dấu phẩy động làm đầu vào và định dạng một chuỗi thập phân chính xác làm đầu ra.

Để đảm bảo chúng tôi đang làm việc với các số dấu phẩy động chính xác, một định dạng chính xác phải được cung cấp làm đầu vào cho chương trình. Định dạng này sẽ là hai số nguyên Significand Exponent, trong đó giá trị dấu phẩy động thực tế là Significand * 2 ^ Exponent. Lưu ý rằng một trong hai giá trị có thể âm.

Cụ thể:

  • Phạm vi và độ chính xác của ít nhất một float 32 bit phải được hỗ trợ (không có đầu vào nào vượt quá điều đó)
  • Giá trị được định dạng thập phân phải là một đại diện chính xác (chỉ cần đủ gần để đảm bảo một đầu tròn chính xác trở lại nổi là không đủ tốt)
  • Chúng tôi không tin tưởng các hàm định dạng dấu phẩy động thư viện chuẩn là đủ chính xác hoặc không đủ nhanh (ví dụ printf:) và do đó chúng có thể không được sử dụng. Bạn phải làm định dạng. Chức năng định dạng / chuyển đổi tích hợp được cho phép.
  • Có thể không có bất kỳ số 0 đứng đầu hoặc dấu nào, ngoại trừ số 0 bắt buộc đứng trước số 0 .nếu không có thành phần số nguyên
  • Một chức năng, hoặc toàn bộ chương trình, được cho phép.

Ví dụ:

1 -2 => 0.25
17 -3 => 2.125
-123 11 => -251904
17 50 => 19140298416324608
23 -13 => 0.0028076171875
3 120 => 3987683987354747618711421180841033728
3 -50 => 0.00000000000000266453525910037569701671600341796875
-3 -50 => -0.00000000000000266453525910037569701671600341796875
10 -2 => 2.5
-12345 -3 => -1543.125
0 0 => 0
161 -4 => 10.0625
512 -3 => 64

Mã ngắn nhất sẽ thắng.


3
Được phép sử dụng số học dấu phẩy động chính xác không giới hạn?
Dennis

2
Nếu số mũ là không âm, chúng ta có thể kết thúc bằng .0không?
Sp3000

@Dennis: Có, số học có độ chính xác cố định không giới hạn hoặc cao được cho phép.
edA-qa mort-ora-y

1
Tôi nghĩ rằng điều đó không nhất quán. Nếu 0.abckhông phải là số 0 đứng đầu, thì đó abc.0không phải là số 0 .
orlp 8/07/2015

1
Đó cũng là quy ước để luôn kết thúc với .0toàn bộ số khi xử lý số dấu phẩy động. Xem ví dụ Python: str(1.0) == '1.0'so str(1) == '1'. Logic của bạn vẫn không nhất quán.
orlp

Câu trả lời:


3

CJam, 43

r_'-&\ize999rim<s1e3'0e[W%999/(i_L?\+'.*sW%

Dùng thử trực tuyến

Giải trình:

Chương trình hoạt động với số mũ lên tới ± 999, gần với độ chính xác gấp đôi (64 bit). Nó tách dấu trừ (nếu có) khỏi ý nghĩa, nhân nó với 10 999 sau đó thực hiện một chút thay đổi với số mũ, giờ đây là một phép tính chính xác. Sau đó, nó đệm sang trái bằng các số 0 nếu kết quả có ít hơn 1000 chữ số, tách 999 chữ số cuối cùng thành phần phân số, loại bỏ các số 0 ở cuối bằng cách chuyển đổi ngược lại thành số nguyên, thêm dấu thập phân nếu cần và đặt mọi thứ lại với nhau.

r_         read and duplicate the significand in string form
'-&        keep only the minus sign, if present
\          swap with the other copy of the significand
iz         convert to integer and get absolute value
e999       multiply by 10^999
ri         read the exponent and convert to integer
m<         shift left by it; negative values will shift right
            the result is an exact non-negative integer
s          convert to string
1e3'0e[    pad to the left with zero characters up to length 1000
            longer strings will be left intact
            we need 1 more than 999 for the 0.xxx case
W%         reverse the string
999/       split into slices of length 999
(          take out the first slice (reversed fractional part)
i          convert to integer
            this removes the leading zeros (trailing in reverse)
_L?        if it's zero, replace with an empty string
\+         concatenate back (to the left) with the second slice
'.*        join the with the dot character
            if the fractional part was zero, we only have the second slice
            (reversed integer part) and there is nothing to join
s          convert to string; this is the reversed result without the sign
W%         reverse back

Cuối cùng, dấu trừ (nếu có) và chuỗi cuối cùng sẽ tự động được in cùng nhau.


2

CJam, 50 byte

q~A1$z#\_0>K5?\z:E#@_s'-&oz*\md_sE'0e[W%isW%'.\+Q?

Đây là một chương trình đầy đủ đọc từ STDIN. Hãy thử trực tuyến trong trình thông dịch CJam .

Xác nhận tất cả các trường hợp thử nghiệm cùng một lúc.


Dựa trên nhận xét của bạn, tôi cho rằng CJam có độ chính xác không giới hạn và bạn đã sử dụng nó ở đây? Có đúng không khi câu trả lời này bao gồm bất kỳ đầu vào nào, không chỉ là float 32 bit? Ngoài ra, chúng ta có thể có được một lời giải thích về cách thức hoạt động?
edA-qa mort-ora-y

CJam có độ chính xác không giới hạn cho các số nguyên, nhưng chỉ có độ chính xác gấp đôi. Tôi nhân với lũy thừa 20 cho số mũ dương và lũy thừa 5 cho số âm, chuyển thành chuỗi và chèn dấu chấm. Tôi sẽ thêm một lời giải thích chi tiết trong một vài giờ.
Dennis

Và có, được cung cấp đủ bộ nhớ, điều này sẽ làm việc cho bất kỳ đầu vào.
Dennis

10 -2 dường như có số 0 ở cuối
aditsu bỏ cuộc vì SE là NGÀY

@aditsu: À đúng rồi, một con số 0 cho mọi sức mạnh của 2 ...
Dennis

2

GNU sed + dc, 65

Điểm bao gồm +1 cho -rtùy chọn của sed .

y/-/_/
s/.*/dc -e"C8k& 2r^*p"/e
s/\\\n//
s/0+$//
s/^(-?)\./\10./

Tôi đã cố gắng để dctrả lời câu trả lời này chỉ C8k& 2r^*pvới số điểm 10, nhưng dccó một số câu hỏi định dạng:

  • dấu hiệu -ve là _thay vì-
  • hàng dài bị phá vỡ với dấu gạch chéo ngược
  • các số 0 ở cuối phải được loại bỏ
  • |n| < 1phải thêm 0 cho

Vì vậy, biểu thức dc được gói và đánh giá bằng cách sedchăm sóc ở trên.

Đầu ra thử nghiệm:

$ echo "1 -2
17 -3
-123 11
17 50
23 -13
3 120
3 -50
-3 -50
8388608 127
1 -127" | sed -rf float.sed
0.25
2.125
-251904
19140298416324608
0.0028076171875
3987683987354747618711421180841033728
0.00000000000000266453525910037569701671600341796875
-0.00000000000000266453525910037569701671600341796875
1427247692705959881058285969449495136382746624
0.0000000000000000000000000000000000000058774717541114375398436826861112283890933277838604376075437585313920862972736358642578125
$ 

Hmm, tôi nghĩ rằng dcloại vi phạm quy tắc của tôi về việc sử dụng chức năng định dạng tiêu chuẩn.
edA-qa mort-ora-y

1
@ edA-qamort-ora-y Tôi cho rằng việc sử dụng dclà ổn, với "số học có độ chính xác cố định không giới hạn hoặc cao được cho phép" . dc's plệnh không phải là một ' dấu chấm động chức năng định dạng' - đó là một chức năng chính xác in tùy ý. Tôi đang đặt độ chính xác đến 128 vị trí thập phân ( C8k), mà tôi nghĩ là quá đủ cho bất kỳ số dư 32 bit nào.
Chấn thương kỹ thuật số
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.