From 9df2df0f9f6916c189d48279c3bd6389ccdb6b49 Mon Sep 17 00:00:00 2001 From: notoria Date: Sat, 2 May 2020 02:36:23 +0200 Subject: [PATCH] Enhanced number_to_rational/2 and number_to_rational/3 --- src/prolog/lib/arithmetic.pl | 63 ++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 35 deletions(-) diff --git a/src/prolog/lib/arithmetic.pl b/src/prolog/lib/arithmetic.pl index 310d08a0..d367d365 100644 --- a/src/prolog/lib/arithmetic.pl +++ b/src/prolog/lib/arithmetic.pl @@ -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), -- 2.54.0