Iāve implemented an optimized float for GMP bigints based on @j4n_bur53 's suggestion of using mpz-get-d
to produce a truncated float and then applying rounding using the rounding mode and MPZ bit level tests, so no allocation required. Precision and rounding mode tests look good to me:
?- aggregate_all(count, (between(1,1000000,N), float(N)**10 =\= float(N^10)), C).
C = 1777.
?- aggregate_all(count, (between(1,1000000,N), -float(N)**10 =\= float(-(N^10))), C).
C = 1763.
?- aggregate_all(count, (between(1,1000000,N), roundtoward(float(-(N**10)),to_positive) > roundtoward(float(-(N**10)),to_negative)), C).
C = 999670.
?- aggregate_all(count, (between(1,1000000,N), roundtoward(float(-(N**10)),to_positive) =:= roundtoward(float(-(N**10)),
C = 330.
?- aggregate_all(count, (between(1,1000000,N), roundtoward(float((N**10)),to_positive) > roundtoward(float((N**10)),to_negative)), C).
C = 999670.
?- aggregate_all(count, (between(1,1000000,N), roundtoward(float((N**10)),to_positive) =:= roundtoward(float((N**10)),to_negative)), C).
C = 330.
On the performance side, here are results for floating small and big ints, and small and big rationals on MacOS-Intel:
?- set_prolog_flag(optimise,true), assert(floatN(N) :- _ is float(N)).
true.
?- N is 42,time((between(1,1000000,_),floatN(N),fail;true)).
% 2,000,000 inferences, 0.167 CPU in 0.167 seconds (100% CPU, 11952786 Lips)
N = 42.
?- N is 2^65+1,time((between(1,1000000,_),floatN(N),fail;true)).
% 2,000,000 inferences, 0.360 CPU in 0.360 seconds (100% CPU, 5554028 Lips)
N = 36893488147419103233.
?- N is 4r3,time((between(1,1000000,_),floatN(N),fail;true)).
% 2,000,000 inferences, 0.534 CPU in 0.534 seconds (100% CPU, 3748140 Lips)
N = 4r3.
?- N is (2^65+1) rdiv 2^65,time((between(1,1000000,_),floatN(N),fail;true)).
% 2,000,000 inferences, 1.092 CPU in 1.092 seconds (100% CPU, 1831623 Lips)
N = 36893488147419103233r36893488147419103232.
Also, for Mac-Intel:
?- X is 978400.0**10.0.
X = 8.038304251093644e+59.
?- X is 978400^10, Y is float(X).
X = 803830425109364419968771652984040429977600000000000000000000,
Y = 8.038304251093644e+59.
?- aggregate_all(sum(S), (between(1,1000000,N),
| S is abs(N^10-float(N)**10)), T).
T = 2.4540871481165494e+46.
Any other suggestions for tests before I generate a PR?