The sprintf
technique is neat, but it has a few disadvantages:
The technique I would prefer is less neat, but easier to verify and more readily made fast: search an array for the boundary case. Have an array with these elements:
10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0, 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0, 100000000000000.0, 1000000000000000.0, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20, 1e+21, 1e+22, 1.0000000000000001e+23, 1.0000000000000001e+24, 1e+25, 1e+26, 1e+27, 1.0000000000000002e+28, 1.0000000000000001e+29, 1e+30, 1.0000000000000001e+31, 1e+32, 1.0000000000000001e+33, 1.0000000000000001e+34, 1.0000000000000002e+35, 1e+36, 1.0000000000000001e+37, 1.0000000000000002e+38, 1.0000000000000001e+39, 1e+40, 1e+41, 1e+42, 1e+43, 1e+44, 1.0000000000000001e+45, 1.0000000000000001e+46, 1e+47, 1e+48, 1.0000000000000001e+49, 1e+50, 1.0000000000000002e+51, 1.0000000000000001e+52, 1.0000000000000002e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1.0000000000000001e+58, 1.0000000000000001e+59, 1.0000000000000001e+60, 1.0000000000000001e+61, 1e+62, 1e+63, 1e+64, 1.0000000000000001e+65, 1.0000000000000001e+66, 1.0000000000000001e+67, 1.0000000000000001e+68, 1e+69, 1e+70, 1e+71, 1.0000000000000001e+72, 1.0000000000000001e+73, 1.0000000000000001e+74, 1.0000000000000001e+75, 1e+76, 1.0000000000000001e+77, 1e+78, 1.0000000000000001e+79, 1e+80, 1.0000000000000001e+81, 1.0000000000000001e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1.0000000000000002e+87, 1.0000000000000001e+88, 1.0000000000000001e+89, 1.0000000000000001e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1.0000000000000001e+98, 1.0000000000000001e+99, 1e+100, 1.0000000000000001e+101, 1.0000000000000001e+102, 1e+103, 1e+104, 1.0000000000000001e+105, 1e+106, 1.0000000000000001e+107, 1e+108, 1.0000000000000002e+109, 1e+110, 1.0000000000000001e+111, 1.0000000000000001e+112, 1e+113, 1e+114, 1e+115, 1e+116, 1e+117, 1.0000000000000001e+118, 1.0000000000000001e+119, 1.0000000000000001e+120, 1e+121, 1e+122, 1.0000000000000001e+123, 1.0000000000000001e+124, 1.0000000000000001e+125, 1.0000000000000001e+126, 1.0000000000000001e+127, 1e+128, 1.0000000000000002e+129, 1e+130, 1.0000000000000001e+131, 1.0000000000000001e+132, 1e+133, 1.0000000000000001e+134, 1.0000000000000001e+135, 1e+136, 1e+137, 1e+138, 1e+139, 1e+140, 1e+141, 1e+142, 1e+143, 1e+144, 1.0000000000000001e+145, 1.0000000000000002e+146, 1.0000000000000002e+147, 1e+148, 1e+149, 1.0000000000000002e+150, 1e+151, 1e+152, 1.0000000000000002e+153, 1e+154, 1e+155, 1.0000000000000002e+156, 1.0000000000000001e+157, 1.0000000000000001e+158, 1.0000000000000001e+159, 1e+160, 1e+161, 1.0000000000000001e+162, 1.0000000000000001e+163, 1e+164, 1.0000000000000001e+165, 1.0000000000000001e+166, 1e+167, 1.0000000000000001e+168, 1.0000000000000001e+169, 1e+170, 1.0000000000000002e+171, 1e+172, 1e+173, 1e+174, 1.0000000000000001e+175, 1e+176, 1e+177, 1e+178, 1.0000000000000001e+179, 1e+180, 1.0000000000000001e+181, 1e+182, 1.0000000000000001e+183, 1e+184, 1.0000000000000001e+185, 1.0000000000000001e+186, 1.0000000000000001e+187, 1e+188, 1e+189, 1e+190, 1e+191, 1e+192, 1e+193, 1.0000000000000001e+194, 1.0000000000000001e+195, 1.0000000000000002e+196, 1.0000000000000001e+197, 1e+198, 1e+199, 1.0000000000000001e+200, 1e+201, 1.0000000000000001e+202, 1.0000000000000002e+203, 1.0000000000000001e+204, 1e+205, 1e+206, 1e+207, 1.0000000000000001e+208, 1e+209, 1.0000000000000001e+210, 1.0000000000000001e+211, 1.0000000000000001e+212, 1.0000000000000001e+213, 1.0000000000000001e+214, 1.0000000000000001e+215, 1e+216, 1.0000000000000001e+217, 1e+218, 1.0000000000000001e+219, 1.0000000000000001e+220, 1e+221, 1e+222, 1e+223, 1.0000000000000002e+224, 1.0000000000000001e+225, 1.0000000000000001e+226, 1e+227, 1.0000000000000001e+228, 1.0000000000000001e+229, 1e+230, 1e+231, 1e+232, 1.0000000000000002e+233, 1e+234, 1e+235, 1e+236, 1.0000000000000001e+237, 1e+238, 1.0000000000000001e+239, 1e+240, 1e+241, 1e+242, 1e+243, 1e+244, 1e+245, 1e+246, 1.0000000000000001e+247, 1e+248, 1.0000000000000001e+249, 1.0000000000000001e+250, 1e+251, 1e+252, 1.0000000000000001e+253, 1.0000000000000001e+254, 1.0000000000000002e+255, 1e+256, 1e+257, 1e+258, 1.0000000000000001e+259, 1e+260, 1.0000000000000001e+261, 1e+262, 1e+263, 1e+264, 1e+265, 1e+266, 1.0000000000000001e+267, 1.0000000000000002e+268, 1e+269, 1e+270, 1.0000000000000001e+271, 1e+272, 1.0000000000000001e+273, 1.0000000000000001e+274, 1.0000000000000001e+275, 1e+276, 1e+277, 1.0000000000000001e+278, 1e+279, 1e+280, 1e+281, 1e+282, 1.0000000000000002e+283, 1e+284, 1.0000000000000001e+285, 1e+286, 1e+287, 1e+288, 1e+289, 1e+290, 1.0000000000000001e+291, 1e+292, 1.0000000000000001e+293, 1e+294, 1.0000000000000001e+295, 1.0000000000000002e+296, 1e+297, 1.0000000000000001e+298, 1e+299, 1e+300, 1e+301, 1e+302, 1e+303, 1.0000000000000001e+304, 1.0000000000000001e+305, 1e+306, 1.0000000000000001e+307, 1e+308
This was generated with this code:
import math
import sys
from decimal import Decimal
def nextafter(x, dir):
m, e = math.frexp(x)
return x + dir * sys.float_info.epsilon * 2.0**(e - 1)
for i in range(1, 320):
pow10 = Decimal(10) ** i
if Decimal(float(pow10)).logb() != i:
pow10 = Decimal(nextafter(float(pow10), 1))
assert Decimal(float(pow10)).logb() == i
assert Decimal(nextafter(float(pow10), -1)).logb() < i
print(float(pow10))
Searching this can be done linearly if speed isn't an issue, which is presumably the case here; otherwise either use a binary search, or (faster) estimate a lower bound using a bit of math, and do a couple of checks to refine that estimate.
0.5
be 1 (because of the leading zero digit) or zero? What shouldNaN
return? Any value returned for+Inf
and-Inf
would be wrong since they require an infinite number of digits, and the return typeint
cannot return+Inf
. \$\endgroup\$