]> Repositorios git - scryer-prolog.git/commitdiff
Enhanced number_to_rational/2 and number_to_rational/3
authornotoria <[email protected]>
Sat, 2 May 2020 00:36:23 +0000 (02:36 +0200)
committernotoria <[email protected]>
Sat, 2 May 2020 00:36:23 +0000 (02:36 +0200)
src/prolog/lib/arithmetic.pl

index 310d08a0aab701214833343778ff46bae483b108..d367d3656af648f7091dec0ee516eb34aa8c4723 100644 (file)
@@ -30,54 +30,47 @@ msb_(X, M, N) :-
     M1 is M + 1,
     msb_(X1, M1, N).
 
-number_to_rational(Real0, Fraction) :-
-    (   var(Real0) -> instantiation_error(number_to_rational/2)
-    ;   Real0 = R1/R2 ->
-        (   member(R, [R1, R2]), \+ number(R) ->
-                type_error(number, R, number_to_rational/2)
-        ;   Real = R1/R2
-        )
-    ;   number(Real0),
-        Real = Real0/1
-    ),
-    number_to_rational(1.0e-6/1, Real, Fraction).
+number_to_rational(Real, Fraction) :-
+    (   var(Real) -> instantiation_error(number_to_rational/2)
+    ;   integer(Real) -> Fraction is Real rdiv 1
+    ;   (rational(Real) ; float(Real)) ->
+            number_to_rational(1.0e-6, Real, Fraction)
+    ;   type_error(number, Real, number_to_rational/2)
+    ).
 
 % If 0 <= Eps0 <= 1e-16 then the search is for "infinite" precision.
 number_to_rational(Eps0, Real0, Fraction) :-
     (   var(Eps0) -> instantiation_error(number_to_rational/3)
-    ;   Eps0 = E0/E1 ->
-        (   member(E, [E0, E1]), \+ number(E) ->
-                type_error(number, E, number_to_rational/3)
-        ;   Eps = E0/E1
-        )
-    ;   number(Eps0),
-        Eps = Eps0/1
+    ;   \+ number(Eps0) -> type_error(number, Eps0, number_to_rational/3)
+    ;   Eps0 < 0 -> domain_error(not_less_than_zero, Eps0, number_to_rational/3)
+    ;   Eps_ is Eps0 rdiv 1,
+        rational_numerator_denominator(Eps_, EpsN, EpsD),
+        Eps = EpsN/EpsD
     ),
     (   var(Real0) -> instantiation_error(number_to_rational/3)
-    ;   Real0 = R1/R2 ->
-        (   member(R, [R1, R2]), \+ number(R) ->
-                type_error(number, R, number_to_rational/3)
-        ;   Real = R1/R2
-        )
-    ;   number(Real0),
-        Real = Real0/1
+    ;   \+ number(Real0) -> type_error(number, Eps0, number_to_rational/3)
+    ;   Real_ is Real0 rdiv 1,
+        rational_numerator_denominator(Real_, RealN, RealD),
+        Real = RealN/RealD
     ),
     E0/E1 = Eps,
     P0/Q0 = Real,
-    S is sign(E0) * sign(E1),
-    (   S < 0 -> domain_error(not_less_than_zero, Eps0, number_to_rational/3)
-    ;   P1 is abs(P0),
-        Q1 is abs(Q0),
-        Qn1n is P1 * E1 - Q1 * E0,
+    (   P0 < 0 -> I1 is -1 + P0 // Q0
+    ;   I1 is P0 // Q0
+    ),
+    P1 is P0 mod Q0,
+    Q1 = Q0,
+    (   P1 =:= 0 -> Fraction is I1 + 0 rdiv 1
+    ;   Qn1n is max(P1 * E1 - Q1 * E0, 0),
         Qn1d is Q1 * E1,
         Qn1 = Qn1n/Qn1d,
         Qp1n is P1 * E1 + Q1 * E0,
         Qp1d = Qn1d,
         Qp1 = Qp1n/Qp1d,
         stern_brocot_(Qn1, Qp1, 0/1, 1/0, P2/Q2),
-        P3 is sign(P0) * sign(Q0) * P2,
-        Fraction is P3 rdiv Q2
-    ).
+        Fraction is I1 + P2 rdiv Q2
+    ),
+    !.
 
 number(X) :-
     (   integer(X)
@@ -98,8 +91,8 @@ stern_brocot_(Qnn/Qnd, Qpn/Qpd, A/B, C/D, Fraction) :-
 
 simplify_fraction(A0/B0, A/B) :-
     G is gcd(A0, B0),
-    A is A0 div G,
-    B is B0 div G.
+    A is A0 // G,
+    B is B0 // G.
 
 rational_numerator_denominator(R, N, D) :-
     write_term_to_chars(R, [], Cs),