Data commit
This commit is contained in:
parent
7387c8f97b
commit
cb5bb5e222
199093 changed files with 3378972 additions and 0 deletions
2
Task/Convert-decimal-number-to-rational/00-META.yaml
Normal file
2
Task/Convert-decimal-number-to-rational/00-META.yaml
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
---
|
||||
from: http://rosettacode.org/wiki/Convert_decimal_number_to_rational
|
||||
18
Task/Convert-decimal-number-to-rational/00-TASK.txt
Normal file
18
Task/Convert-decimal-number-to-rational/00-TASK.txt
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
The task is to write a program to transform a decimal number into a fraction in lowest terms.
|
||||
|
||||
It is not always possible to do this exactly. For instance, while rational numbers can be converted to decimal representation, some of them need an infinite number of digits to be represented exactly in decimal form. Namely, [[wp:Repeating decimal|repeating decimals]] such as 1/3 = 0.333...
|
||||
|
||||
Because of this, the following fractions cannot be obtained (reliably) unless the language has some way of representing repeating decimals:
|
||||
* 67 / 74 = 0.9(054) = 0.9054054...
|
||||
* 14 / 27 = 0.(518) = 0.518518...
|
||||
|
||||
<br>Acceptable output:
|
||||
|
||||
* 0.9054054 → 4527027 / 5000000
|
||||
* 0.518518 → 259259 / 500000
|
||||
|
||||
<br>Finite decimals are of course no problem:
|
||||
|
||||
* 0.75 → 3 / 4
|
||||
<br><br>
|
||||
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
T Rational
|
||||
Int numerator
|
||||
Int denominator
|
||||
|
||||
F (numerator, denominator)
|
||||
.numerator = numerator
|
||||
.denominator = denominator
|
||||
|
||||
F String()
|
||||
I .denominator == 1
|
||||
R String(.numerator)
|
||||
E
|
||||
R .numerator‘//’(.denominator)
|
||||
|
||||
F rationalize(x, tol = 1e-12)
|
||||
V xx = x
|
||||
V flagNeg = xx < 0.0
|
||||
I flagNeg
|
||||
xx = -xx
|
||||
I xx < 1e-10
|
||||
R Rational(0, 1)
|
||||
I abs(xx - round(xx)) < tol
|
||||
R Rational(Int(xx), 1)
|
||||
V a = 0
|
||||
V b = 1
|
||||
V c = Int(ceil(xx))
|
||||
V d = 1
|
||||
V aux1 = 7FFF'FFFF I/ 2
|
||||
L c < aux1 & d < aux1
|
||||
V aux2 = (Float(a) + Float(c)) / (Float(b) + Float(d))
|
||||
I abs(xx - aux2) < tol
|
||||
L.break
|
||||
I xx > aux2
|
||||
a += c
|
||||
b += d
|
||||
E
|
||||
c += a
|
||||
d += b
|
||||
V g = gcd(a + c, b + d)
|
||||
I flagNeg
|
||||
R Rational(-(a + c) I/ g, (b + d) I/ g)
|
||||
E
|
||||
R Rational((a + c) I/ g, (b + d) I/ g)
|
||||
|
||||
print(rationalize(0.9054054054))
|
||||
print(rationalize(0.9054054054, 0.0001))
|
||||
print(rationalize(0.5185185185))
|
||||
print(rationalize(0.5185185185, 0.0001))
|
||||
print(rationalize(0.75))
|
||||
print(rationalize(0.1428571428, 0.001))
|
||||
print(rationalize(35.000))
|
||||
print(rationalize(35.001))
|
||||
print(rationalize(0.9))
|
||||
print(rationalize(0.99))
|
||||
print(rationalize(0.909))
|
||||
print(rationalize(0.909, 0.001))
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
generic
|
||||
type Real is digits <>;
|
||||
procedure Real_To_Rational(R: Real;
|
||||
Bound: Positive;
|
||||
Nominator: out Integer;
|
||||
Denominator: out Positive);
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
procedure Real_To_Rational (R: Real;
|
||||
Bound: Positive;
|
||||
Nominator: out Integer;
|
||||
Denominator: out Positive) is
|
||||
Error: Real;
|
||||
Best: Positive := 1;
|
||||
Best_Error: Real := Real'Last;
|
||||
begin
|
||||
if R = 0.0 then
|
||||
Nominator := 0;
|
||||
Denominator := 1;
|
||||
return;
|
||||
elsif R < 0.0 then
|
||||
Real_To_Rational(-R, Bound, Nominator, Denominator);
|
||||
Nominator := - Nominator;
|
||||
return;
|
||||
else
|
||||
for I in 1 .. Bound loop
|
||||
Error := abs(Real(I) * R - Real'Rounding(Real(I) * R));
|
||||
if Error < Best_Error then
|
||||
Best := I;
|
||||
Best_Error := Error;
|
||||
end if;
|
||||
end loop;
|
||||
end if;
|
||||
Denominator := Best;
|
||||
Nominator := Integer(Real'Rounding(Real(Denominator) * R));
|
||||
|
||||
end Real_To_Rational;
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
with Ada.Text_IO; With Real_To_Rational;
|
||||
|
||||
procedure Convert_Decimal_To_Rational is
|
||||
|
||||
type My_Real is new Long_Float; -- change this for another "Real" type
|
||||
|
||||
package FIO is new Ada.Text_IO.Float_IO(My_Real);
|
||||
procedure R2R is new Real_To_Rational(My_Real);
|
||||
|
||||
Nom, Denom: Integer;
|
||||
R: My_Real;
|
||||
|
||||
begin
|
||||
loop
|
||||
Ada.Text_IO.New_Line;
|
||||
FIO.Get(R);
|
||||
FIO.Put(R, Fore => 2, Aft => 9, Exp => 0);
|
||||
exit when R = 0.0;
|
||||
for I in 0 .. 4 loop
|
||||
R2R(R, 10**I, Nom, Denom);
|
||||
Ada.Text_IO.Put(" " & Integer'Image(Nom) &
|
||||
" /" & Integer'Image(Denom));
|
||||
end loop;
|
||||
end loop;
|
||||
end Convert_Decimal_To_Rational;
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
--------- RATIONAL APPROXIMATION TO DECIMAL NUMBER -------
|
||||
|
||||
-- approxRatio :: Real -> Real -> Ratio
|
||||
on approxRatio(epsilon, n)
|
||||
if {real, integer} contains (class of epsilon) and 0 < epsilon then
|
||||
-- Given
|
||||
set e to epsilon
|
||||
else
|
||||
-- Default
|
||||
set e to 1 / 10000
|
||||
end if
|
||||
|
||||
script gcde
|
||||
on |λ|(e, x, y)
|
||||
script _gcd
|
||||
on |λ|(a, b)
|
||||
if b < e then
|
||||
a
|
||||
else
|
||||
|λ|(b, a mod b)
|
||||
end if
|
||||
end |λ|
|
||||
end script
|
||||
|λ|(abs(x), abs(y)) of _gcd
|
||||
end |λ|
|
||||
end script
|
||||
|
||||
set c to |λ|(e, 1, n) of gcde
|
||||
Ratio((n div c), (1 div c))
|
||||
end approxRatio
|
||||
|
||||
|
||||
-- Ratio :: Int -> Int -> Ratio
|
||||
on Ratio(n, d)
|
||||
{type:"Ratio", n:n, d:d}
|
||||
end Ratio
|
||||
|
||||
|
||||
-- showRatio :: Ratio -> String
|
||||
on showRatio(r)
|
||||
(n of r as string) & "/" & (d of r as string)
|
||||
end showRatio
|
||||
|
||||
|
||||
--------------------------- TEST -------------------------
|
||||
on run
|
||||
script ratioString
|
||||
-- Using a tolerance epsilon of 1/10000
|
||||
on |λ|(x)
|
||||
(x as string) & " -> " & showRatio(approxRatio(1.0E-4, x))
|
||||
end |λ|
|
||||
end script
|
||||
|
||||
unlines(map(ratioString, ¬
|
||||
{0.9054054, 0.518518, 0.75}))
|
||||
|
||||
-- 0.9054054 -> 67/74
|
||||
-- 0.518518 -> 14/27
|
||||
-- 0.75 -> 3/4
|
||||
end run
|
||||
|
||||
|
||||
-------------------- GENERIC FUNCTIONS -------------------
|
||||
|
||||
-- abs :: Num -> Num
|
||||
on abs(x)
|
||||
if 0 > x then
|
||||
-x
|
||||
else
|
||||
x
|
||||
end if
|
||||
end abs
|
||||
|
||||
|
||||
-- Lift 2nd class handler function into 1st class script wrapper
|
||||
-- mReturn :: First-class m => (a -> b) -> m (a -> b)
|
||||
on mReturn(f)
|
||||
if class of f is script then
|
||||
f
|
||||
else
|
||||
script
|
||||
property |λ| : f
|
||||
end script
|
||||
end if
|
||||
end mReturn
|
||||
|
||||
|
||||
-- map :: (a -> b) -> [a] -> [b]
|
||||
on map(f, xs)
|
||||
tell mReturn(f)
|
||||
set lng to length of xs
|
||||
set lst to {}
|
||||
repeat with i from 1 to lng
|
||||
set end of lst to |λ|(item i of xs, i, xs)
|
||||
end repeat
|
||||
return lst
|
||||
end tell
|
||||
end map
|
||||
|
||||
|
||||
-- unlines :: [String] -> String
|
||||
on unlines(xs)
|
||||
-- A single string formed by the intercalation
|
||||
-- of a list of strings with the newline character.
|
||||
set {dlm, my text item delimiters} to ¬
|
||||
{my text item delimiters, linefeed}
|
||||
set s to xs as text
|
||||
set my text item delimiters to dlm
|
||||
s
|
||||
end unlines
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
Array := []
|
||||
inputbox, string, Enter Number
|
||||
stringsplit, string, string, .
|
||||
if ( string1 = 0 )
|
||||
string1 =
|
||||
loop, parse, string, .
|
||||
if A_index = 2
|
||||
loop, parse, A_loopfield
|
||||
Array[A_index] := A_loopfield, k := A_index
|
||||
if (k = 1)
|
||||
{
|
||||
numerator := Array[1]
|
||||
Denominator := 10
|
||||
goto label
|
||||
}
|
||||
Original1 := K
|
||||
To_rn := floor(k/2)
|
||||
M_M := k - To_rn
|
||||
Original2 := k - To_rn
|
||||
loop
|
||||
{
|
||||
loop, % To_rn
|
||||
|
||||
{
|
||||
Check1 .= Array[k]
|
||||
Check2 .= Array[M_M]
|
||||
k--
|
||||
m_M--
|
||||
}
|
||||
if ( check1 = check2 )
|
||||
{
|
||||
;~ process beginsTO check;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
loop, % To_rn
|
||||
nines .= 9
|
||||
loop, % k - TO_rn
|
||||
Zeroes .= 0
|
||||
loop % k - TO_rn
|
||||
Minus .= Array[A_index]
|
||||
loop % k
|
||||
Plus .= Array[A_index]
|
||||
if ( minus = "" )
|
||||
minus := 0
|
||||
Numerator := Plus - minus
|
||||
Denominator := Nines . Zeroes
|
||||
;;;;;;;;;;;;;HCF
|
||||
goto, label
|
||||
}
|
||||
Check1 =
|
||||
check2 =
|
||||
k := Original1
|
||||
m_M := original2 + A_index
|
||||
TO_rn--
|
||||
if ( to_rn = 0 )
|
||||
{
|
||||
zeroes =
|
||||
loop % original1
|
||||
zeroes .= 0
|
||||
Denominator := 1 . zeroes
|
||||
numerator := string2
|
||||
goto, label
|
||||
}
|
||||
}
|
||||
esc::Exitapp
|
||||
label:
|
||||
Index := 2
|
||||
loop
|
||||
{
|
||||
|
||||
if (mod(denominator, numerator) = 0 )
|
||||
HCF := numerator
|
||||
if ( index = floor(numerator/2) )
|
||||
break
|
||||
if ( mod(numerator, index) = 0 ) && ( mod(denominator, index) = 0 )
|
||||
{
|
||||
HCF = %index%
|
||||
index++
|
||||
}
|
||||
else
|
||||
index++
|
||||
}
|
||||
if ( HCF = "" )
|
||||
Ans := numerator "/" Denominator
|
||||
else
|
||||
Ans := floor(numerator/HCF) "/" floor(Denominator/HCF)
|
||||
MsgBox % String . " -> " . String1 . " " . Ans
|
||||
reload
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
( ( exact
|
||||
= integerPart decimalPart z
|
||||
. @(!arg:?integerPart "." ?decimalPart)
|
||||
& !integerPart
|
||||
+ ( @( !decimalPart
|
||||
: (? ((%@:~0) ?:?decimalPart)) [?z
|
||||
)
|
||||
& !decimalPart*10^(-1*!z)
|
||||
| 0
|
||||
)
|
||||
| !arg
|
||||
)
|
||||
& ( approximation
|
||||
= integerPart firstDecimals repeatingDecimals
|
||||
, x y z z-y x-y numerator denominator
|
||||
. @( !arg
|
||||
: ?integerPart
|
||||
"."
|
||||
[?x
|
||||
?firstDecimals
|
||||
?repeatingDecimals
|
||||
[?y
|
||||
!repeatingDecimals
|
||||
[?z
|
||||
)
|
||||
& !z+-1*!y:?z-y
|
||||
& !x+-1*!y:?x-y
|
||||
& 10:?numerator:?denominator
|
||||
& ( !z-y:0&0:?repeatingDecimals
|
||||
| 9:?denominator
|
||||
& whl
|
||||
' ( !z+-1:>!y:?z
|
||||
& !numerator*10:?numerator
|
||||
& !denominator*10+9:?denominator
|
||||
)
|
||||
& @(!repeatingDecimals:? #?repeatingDecimals)
|
||||
)
|
||||
& ( @(!firstDecimals:? #?firstDecimals)
|
||||
| 0:?firstDecimals
|
||||
)
|
||||
& !integerPart
|
||||
+ !firstDecimals*10^(!x-y+!z-y)
|
||||
+ !numerator*!denominator^-1*!repeatingDecimals*10^!x-y
|
||||
)
|
||||
& "0.9054054054"
|
||||
"0.5185185185"
|
||||
"0.75"
|
||||
"0.905405400"
|
||||
"0.1428571428"
|
||||
"35.000"
|
||||
"35.001"
|
||||
"0.00000000001"
|
||||
"0.000001000001"
|
||||
"0.9"
|
||||
"0.99"
|
||||
"0.909"
|
||||
"0.9090"
|
||||
"0.90909"
|
||||
: ?decs
|
||||
& whl
|
||||
' ( !decs:%?dec ?decs
|
||||
& approximation$!dec:?approx
|
||||
& out
|
||||
$ ( !dec
|
||||
"="
|
||||
(exact$!dec:?precise)
|
||||
( !approx:!precise&
|
||||
| str$("(approx. " !approx ")")
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace RosettaDecimalToFraction
|
||||
{
|
||||
public class Fraction
|
||||
{
|
||||
public Int64 Numerator;
|
||||
public Int64 Denominator;
|
||||
public Fraction(double f, Int64 MaximumDenominator = 4096)
|
||||
{
|
||||
/* Translated from the C version. */
|
||||
/* a: continued fraction coefficients. */
|
||||
Int64 a;
|
||||
var h = new Int64[3] { 0, 1, 0 };
|
||||
var k = new Int64[3] { 1, 0, 0 };
|
||||
Int64 x, d, n = 1;
|
||||
int i, neg = 0;
|
||||
|
||||
if (MaximumDenominator <= 1)
|
||||
{
|
||||
Denominator = 1;
|
||||
Numerator = (Int64)f;
|
||||
return;
|
||||
}
|
||||
|
||||
if (f < 0) { neg = 1; f = -f; }
|
||||
|
||||
while (f != Math.Floor(f)) { n <<= 1; f *= 2; }
|
||||
d = (Int64)f;
|
||||
|
||||
/* continued fraction and check denominator each step */
|
||||
for (i = 0; i < 64; i++)
|
||||
{
|
||||
a = (n != 0) ? d / n : 0;
|
||||
if ((i != 0) && (a == 0)) break;
|
||||
|
||||
x = d; d = n; n = x % n;
|
||||
|
||||
x = a;
|
||||
if (k[1] * a + k[0] >= MaximumDenominator)
|
||||
{
|
||||
x = (MaximumDenominator - k[0]) / k[1];
|
||||
if (x * 2 >= a || k[1] >= MaximumDenominator)
|
||||
i = 65;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
h[2] = x * h[1] + h[0]; h[0] = h[1]; h[1] = h[2];
|
||||
k[2] = x * k[1] + k[0]; k[0] = k[1]; k[1] = k[2];
|
||||
}
|
||||
Denominator = k[1];
|
||||
Numerator = neg != 0 ? -h[1] : h[1];
|
||||
}
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("{0} / {1}", Numerator, Denominator);
|
||||
}
|
||||
}
|
||||
class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Console.OutputEncoding = UTF8Encoding.UTF8;
|
||||
foreach (double d in new double[] { 0.9054054, 0.518518, 0.75, 0.4285714, 0.833333,
|
||||
0.90909, 3.14159265358979, 2.7182818284590451 })
|
||||
{
|
||||
var f = new Fraction(d, d >= 2 ? 65536 : 4096);
|
||||
Console.WriteLine("{0,20} → {1}", d, f);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/* f : number to convert.
|
||||
* num, denom: returned parts of the rational.
|
||||
* md: max denominator value. Note that machine floating point number
|
||||
* has a finite resolution (10e-16 ish for 64 bit double), so specifying
|
||||
* a "best match with minimal error" is often wrong, because one can
|
||||
* always just retrieve the significand and return that divided by
|
||||
* 2**52, which is in a sense accurate, but generally not very useful:
|
||||
* 1.0/7.0 would be "2573485501354569/18014398509481984", for example.
|
||||
*/
|
||||
void rat_approx(double f, int64_t md, int64_t *num, int64_t *denom)
|
||||
{
|
||||
/* a: continued fraction coefficients. */
|
||||
int64_t a, h[3] = { 0, 1, 0 }, k[3] = { 1, 0, 0 };
|
||||
int64_t x, d, n = 1;
|
||||
int i, neg = 0;
|
||||
|
||||
if (md <= 1) { *denom = 1; *num = (int64_t) f; return; }
|
||||
|
||||
if (f < 0) { neg = 1; f = -f; }
|
||||
|
||||
while (f != floor(f)) { n <<= 1; f *= 2; }
|
||||
d = f;
|
||||
|
||||
/* continued fraction and check denominator each step */
|
||||
for (i = 0; i < 64; i++) {
|
||||
a = n ? d / n : 0;
|
||||
if (i && !a) break;
|
||||
|
||||
x = d; d = n; n = x % n;
|
||||
|
||||
x = a;
|
||||
if (k[1] * a + k[0] >= md) {
|
||||
x = (md - k[0]) / k[1];
|
||||
if (x * 2 >= a || k[1] >= md)
|
||||
i = 65;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
h[2] = x * h[1] + h[0]; h[0] = h[1]; h[1] = h[2];
|
||||
k[2] = x * k[1] + k[0]; k[0] = k[1]; k[1] = k[2];
|
||||
}
|
||||
*denom = k[1];
|
||||
*num = neg ? -h[1] : h[1];
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int i;
|
||||
int64_t d, n;
|
||||
double f;
|
||||
|
||||
printf("f = %16.14f\n", f = 1.0/7);
|
||||
for (i = 1; i <= 20000000; i *= 16) {
|
||||
printf("denom <= %d: ", i);
|
||||
rat_approx(f, i, &n, &d);
|
||||
printf("%lld/%lld\n", n, d);
|
||||
}
|
||||
|
||||
printf("\nf = %16.14f\n", f = atan2(1,1) * 4);
|
||||
for (i = 1; i <= 20000000; i *= 16) {
|
||||
printf("denom <= %d: ", i);
|
||||
rat_approx(f, i, &n, &d);
|
||||
printf("%lld/%lld\n", n, d);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
f = 0.14285714285714
|
||||
denom <= 1: 0/1
|
||||
denom <= 16: 1/7
|
||||
denom <= 256: 1/7
|
||||
denom <= 4096: 1/7
|
||||
denom <= 65536: 1/7
|
||||
denom <= 1048576: 1/7
|
||||
denom <= 16777216: 1/7
|
||||
|
||||
f = 3.14159265358979
|
||||
denom <= 1: 3/1
|
||||
denom <= 16: 22/7
|
||||
denom <= 256: 355/113
|
||||
denom <= 4096: 355/113
|
||||
denom <= 65536: 104348/33215
|
||||
denom <= 1048576: 3126535/995207
|
||||
denom <= 16777216: 47627751/15160384
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
import std.stdio, std.math, std.string, std.typecons;
|
||||
|
||||
alias Fraction = Tuple!(int,"nominator", uint,"denominator");
|
||||
|
||||
Fraction real2Rational(in real r, in uint bound) /*pure*/ nothrow {
|
||||
if (r == 0.0) {
|
||||
return Fraction(0, 1);
|
||||
} else if (r < 0.0) {
|
||||
auto result = real2Rational(-r, bound);
|
||||
result.nominator = -result.nominator;
|
||||
return result;
|
||||
} else {
|
||||
uint best = 1;
|
||||
real bestError = real.max;
|
||||
|
||||
foreach (i; 1 .. bound + 1) {
|
||||
// round is not pure.
|
||||
immutable real error = abs(i * r - round(i * r));
|
||||
if (error < bestError) {
|
||||
best = i;
|
||||
bestError = error;
|
||||
}
|
||||
}
|
||||
|
||||
return Fraction(cast(int)round(best * r), best);
|
||||
}
|
||||
}
|
||||
|
||||
void main() {
|
||||
immutable tests = [ 0.750000000, 0.518518000, 0.905405400,
|
||||
0.142857143, 3.141592654, 2.718281828,
|
||||
-0.423310825, 31.415926536];
|
||||
|
||||
foreach (r; tests) {
|
||||
writef("%8.9f ", r);
|
||||
foreach (i; 0 .. 5)
|
||||
writef(" %d/%d", real2Rational(r, 10 ^^ i).tupleof);
|
||||
writeln();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
program Convert_decimal_number_to_rational;
|
||||
|
||||
{$APPTYPE CONSOLE}
|
||||
|
||||
uses
|
||||
Velthuis.BigRationals,
|
||||
Velthuis.BigDecimals;
|
||||
|
||||
const
|
||||
Tests: TArray<string> = ['0.9054054', '0.518518', '0.75'];
|
||||
|
||||
var
|
||||
Rational: BigRational;
|
||||
Decimal: BigDecimal;
|
||||
|
||||
begin
|
||||
for var test in Tests do
|
||||
begin
|
||||
Decimal := test;
|
||||
Rational := Decimal;
|
||||
Writeln(test, ' = ', Rational.ToString);
|
||||
end;
|
||||
Readln;
|
||||
end.
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
(exact->inexact 67/74)
|
||||
→ 0.9054054054054054
|
||||
(inexact->exact 0.9054054054054054)
|
||||
→ 67/74
|
||||
|
||||
(rationalize 0.7978723404255319)
|
||||
→ 75/94
|
||||
|
||||
;; finding rational approximations of PI
|
||||
(for ((ε (in-range -1 -15 -1)))
|
||||
(writeln ( format "precision:10^%d %t PI = %d" ε
|
||||
(rationalize PI (expt 10 e)))))
|
||||
|
||||
"precision:10^-1 PI = 16/5"
|
||||
"precision:10^-2 PI = 22/7" ;;🎩
|
||||
"precision:10^-3 PI = 201/64"
|
||||
"precision:10^-4 PI = 333/106"
|
||||
"precision:10^-5 PI = 355/113" ;; 🎩 🎩
|
||||
"precision:10^-6 PI = 355/113"
|
||||
"precision:10^-7 PI = 75948/24175"
|
||||
"precision:10^-8 PI = 100798/32085"
|
||||
"precision:10^-9 PI = 103993/33102"
|
||||
"precision:10^-10 PI = 312689/99532"
|
||||
"precision:10^-11 PI = 833719/265381"
|
||||
"precision:10^-12 PI = 4272943/1360120"
|
||||
"precision:10^-13 PI = 5419351/1725033"
|
||||
"precision:10^-14 PI = 58466453/18610450"
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
USING: kernel math.floating-point prettyprint ;
|
||||
|
||||
0.9054054 0.518518 0.75 [ double>ratio . ] tri@
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
\ Brute force search, optimized to search only within integer bounds surrounding target
|
||||
\ Forth 200x compliant
|
||||
|
||||
: RealToRational ( float_target int_denominator_limit -- numerator denominator )
|
||||
{: f: thereal denlimit | realscale numtor denom neg? f: besterror f: temperror :}
|
||||
0 to numtor
|
||||
0 to denom
|
||||
9999999e to besterror \ very large error that will surely be improved upon
|
||||
thereal F0< to neg? \ save sign for later
|
||||
thereal FABS to thereal
|
||||
|
||||
thereal FTRUNC f>s 1+ to realscale \ realscale helps set integer bounds around target
|
||||
|
||||
denlimit 1+ 1 ?DO \ search through possible denominators ( 1 to denlimit)
|
||||
|
||||
I realscale * I realscale 1- * ?DO \ search within integer limits bounding the real
|
||||
I s>f J s>f F/ \ e.g. for 3.1419e search only between 3 and 4
|
||||
thereal F- FABS to temperror
|
||||
|
||||
temperror besterror F< IF
|
||||
temperror to besterror I to numtor J to denom
|
||||
THEN
|
||||
LOOP
|
||||
|
||||
LOOP
|
||||
|
||||
neg? IF numtor NEGATE to numtor THEN
|
||||
|
||||
numtor denom
|
||||
;
|
||||
(run)
|
||||
1.618033988e 100 RealToRational swap . . 144 89
|
||||
3.14159e 1000 RealToRational swap . . 355 113
|
||||
2.71828e 1000 RealToRational swap . . 1264 465
|
||||
0.9054054e 100 RealToRational swap . . 67 74
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
MODULE PQ !Plays with some integer arithmetic.
|
||||
INTEGER MSG !Output unit number.
|
||||
CONTAINS !One good routine.
|
||||
INTEGER FUNCTION GCD(I,J) !Greatest common divisor.
|
||||
INTEGER I,J !Of these two integers.
|
||||
INTEGER N,M,R !Workers.
|
||||
N = MAX(I,J) !Since I don't want to damage I or J,
|
||||
M = MIN(I,J) !These copies might as well be the right way around.
|
||||
1 R = MOD(N,M) !Divide N by M to get the remainder R.
|
||||
IF (R.GT.0) THEN !Remainder zero?
|
||||
N = M !No. Descend a level.
|
||||
M = R !M-multiplicity has been removed from N.
|
||||
IF (R .GT. 1) GO TO 1 !No point dividing by one.
|
||||
END IF !If R = 0, M divides N.
|
||||
GCD = M !There we are.
|
||||
END FUNCTION GCD !Euclid lives on!
|
||||
|
||||
SUBROUTINE RATIONAL10(X)!By contrast, this is rather crude.
|
||||
DOUBLE PRECISION X !The number.
|
||||
DOUBLE PRECISION R !Its latest rational approach.
|
||||
INTEGER P,Q !For R = P/Q.
|
||||
INTEGER F,WHACK !Assistants.
|
||||
PARAMETER (WHACK = 10**8) !The rescale...
|
||||
P = X*WHACK + 0.5 !Multiply by WHACK/WHACK = 1 and round to integer.
|
||||
Q = WHACK !Thus compute X/1, sortof.
|
||||
F = GCD(P,Q) !Perhaps there is a common factor.
|
||||
P = P/F !Divide it out.
|
||||
Q = Q/F !For a proper rational number.
|
||||
R = DBLE(P)/DBLE(Q) !So, where did we end up?
|
||||
WRITE (MSG,1) P,Q,X - R,WHACK !Details.
|
||||
1 FORMAT ("x - ",I0,"/",I0,T28," = ",F18.14,
|
||||
1 " via multiplication by ",I0)
|
||||
END SUBROUTINE RATIONAL10 !Enough of this.
|
||||
|
||||
SUBROUTINE RATIONAL(X) !Use brute force in a different way.
|
||||
DOUBLE PRECISION X !The number.
|
||||
DOUBLE PRECISION R,E,BEST !Assistants.
|
||||
INTEGER P,Q !For R = P/Q.
|
||||
INTEGER TRY,F !Floundering.
|
||||
P = 1 + X !Prevent P = 0.
|
||||
Q = 1 !So, X/1, sortof.
|
||||
BEST = X*6 !A largeish value for the first try.
|
||||
DO TRY = 1,10000000 !Pound away.
|
||||
R = DBLE(P)/DBLE(Q) !The current approximation.
|
||||
E = X - R !Deviation.
|
||||
IF (ABS(E) .LE. BEST) THEN !Significantly better than before?
|
||||
BEST = ABS(E)*0.125 !Yes. Demand eightfold improvement to notice.
|
||||
F = GCD(P,Q) !We may land on a multiple.
|
||||
IF (BEST.LT.0.1D0) WRITE (MSG,1) P/F,Q/F,E !Skip early floundering.
|
||||
1 FORMAT ("x - ",I0,"/",I0,T28," = ",F18.14) !Try to align columns.
|
||||
IF (F.NE.1) WRITE (MSG,*) "Common factor!",F !A surprise!
|
||||
IF (E.EQ.0) EXIT !Perhaps we landed a direct hit?
|
||||
END IF !So much for possible announcements.
|
||||
IF (E.GT.0) THEN !Is R too small?
|
||||
P = P + CEILING(E*Q) !Yes. Make P bigger by the shortfall.
|
||||
ELSE IF (E .LT. 0) THEN !But perhaps R is too big?
|
||||
Q = Q + 1 !If so, use a smaller interval.
|
||||
END IF !So much for adjustments.
|
||||
END DO !Try again.
|
||||
END SUBROUTINE RATIONAL !Limited integers, limited sense.
|
||||
|
||||
SUBROUTINE RATIONALISE(X,WOT) !Run the tests.
|
||||
DOUBLE PRECISION X !The value.
|
||||
CHARACTER*(*) WOT !Some blather.
|
||||
WRITE (MSG,*) X,WOT !Explanations can help.
|
||||
CALL RATIONAL10(X) !Try a crude method.
|
||||
CALL RATIONAL(X) !Try a laborious method.
|
||||
WRITE (MSG,*) !Space off.
|
||||
END SUBROUTINE RATIONALISE !That wasn't much fun.
|
||||
END MODULE PQ !But computer time is cheap.
|
||||
|
||||
PROGRAM APPROX
|
||||
USE PQ
|
||||
DOUBLE PRECISION PI,E
|
||||
MSG = 6
|
||||
WRITE (MSG,*) "Rational numbers near to decimal values."
|
||||
WRITE (MSG,*)
|
||||
PI = 1 !Thus get a double precision conatant.
|
||||
PI = 4*ATAN(PI) !That will determine the precision of ATAN.
|
||||
E = DEXP(1.0D0) !Rather than blabber on about 1 in double precision.
|
||||
CALL RATIONALISE(0.1D0,"1/10 Repeating in binary..")
|
||||
CALL RATIONALISE(3.14159D0,"Pi approx.")
|
||||
CALL RATIONALISE(PI,"Pi approximated better.")
|
||||
CALL RATIONALISE(E,"e: rational approximations aren't much use.")
|
||||
CALL RATIONALISE(10.15D0,"Exact in decimal, recurring in binary.")
|
||||
WRITE (MSG,*)
|
||||
WRITE (MSG,*) "Variations on 67/74"
|
||||
CALL RATIONALISE(0.9054D0,"67/74 = 0·9(054) repeating in base 10")
|
||||
CALL RATIONALISE(0.9054054D0,"Two repeats.")
|
||||
CALL RATIONALISE(0.9054054054D0,"Three repeats.")
|
||||
WRITE (MSG,*)
|
||||
WRITE (MSG,*) "Variations on 14/27"
|
||||
CALL RATIONALISE(0.518D0,"14/27 = 0·(518) repeating in decimal.")
|
||||
CALL RATIONALISE(0.519D0,"Rounded.")
|
||||
CALL RATIONALISE(0.518518D0,"Two repeats, truncated.")
|
||||
CALL RATIONALISE(0.518519D0,"Two repeats, rounded.")
|
||||
END
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
'' Written in FreeBASIC
|
||||
'' (no error checking, limited to 64-bit signed math)
|
||||
type number as longint
|
||||
#define str2num vallng
|
||||
#define pow10(n) clngint(10 ^ (n))
|
||||
|
||||
function gcd(a as number, b as number) as number
|
||||
if a = 0 then return b
|
||||
return gcd(b mod a, a)
|
||||
end function
|
||||
|
||||
|
||||
function parserational(n as const string) as string
|
||||
dim as string whole, dec, num, denom
|
||||
dim as number iwhole, idec, inum, idenom, igcd
|
||||
|
||||
'' find positions of '.', '(' and ')' in code
|
||||
dim as integer dpos, r1pos, r2pos
|
||||
dpos = instr(n & ".", ".")
|
||||
r1pos = instr(n & "(", "(")
|
||||
r2pos = instr(n & ")", ")")
|
||||
|
||||
'' extract sections of number (whole, decimal, repeated numerator), generate '999' denominator
|
||||
whole = left(n, dpos - 1)
|
||||
dec = mid(n, dpos + 1, r1pos - dpos - 1)
|
||||
num = mid(n, r1pos + 1, r2pos - r1pos - 1)
|
||||
denom = string(len(num), "9"): if denom = "" then denom = "1"
|
||||
|
||||
'' parse sections to integer
|
||||
iwhole = str2num(whole)
|
||||
idec = str2num(dec)
|
||||
inum = str2num(num)
|
||||
idenom = str2num(denom)
|
||||
|
||||
'' if whole was negative, decimal and repeated sections need to be negative too
|
||||
if left(ltrim(whole), 1) = "-" then idec = -idec: inum = -inum
|
||||
|
||||
'' add decimal part to repeated fraction, and scale down
|
||||
inum += idec * idenom
|
||||
idenom *= pow10(len(dec))
|
||||
|
||||
'' add integer part to fraction
|
||||
inum += iwhole * idenom
|
||||
|
||||
'' simplify fraction
|
||||
igcd = abs(gcd(inum, idenom))
|
||||
if igcd <> 0 then
|
||||
inum \= igcd
|
||||
idenom \= igcd
|
||||
end if
|
||||
|
||||
return inum & " / " & idenom & " = " & (inum / idenom)
|
||||
|
||||
end function
|
||||
|
||||
data "0.9(054)", "0.(518)", "-.12(345)", ""
|
||||
do
|
||||
dim as string n
|
||||
read n
|
||||
if n = "" then exit do
|
||||
print n & ":", parserational(n)
|
||||
loop
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
func main() {
|
||||
for _, d := range []string{"0.9054054", "0.518518", "0.75"} {
|
||||
if r, ok := new(big.Rat).SetString(d); ok {
|
||||
fmt.Println(d, "=", r)
|
||||
} else {
|
||||
fmt.Println(d, "invalid decimal number")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
Number.metaClass.mixin RationalCategory
|
||||
|
||||
[
|
||||
0.9054054, 0.518518, 0.75, Math.E, -0.423310825, Math.PI, 0.111111111111111111111111
|
||||
].each{
|
||||
printf "%30.27f %s\n", it, it as Rational
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
Prelude> map (\d -> Ratio.approxRational d 0.0001) [0.9054054, 0.518518, 0.75]
|
||||
[67 % 74,14 % 27,3 % 4]
|
||||
Prelude> [0.9054054, 0.518518, 0.75] :: [Rational]
|
||||
[4527027 % 5000000,259259 % 500000,3 % 4]
|
||||
Prelude> map (fst . head . Numeric.readFloat) ["0.9054054", "0.518518", "0.75"] :: [Rational]
|
||||
[4527027 % 5000000,259259 % 500000,3 % 4]
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
x: 0.9054054 0.518518 0.75 NB. find "exact" rational representation
|
||||
127424481939351r140737488355328 866492568306r1671094481399 3r4
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
x: 0.9 0.5
|
||||
9r10 1r2
|
||||
x: 0.9054 0.5185
|
||||
4527r5000 1037r2000
|
||||
x: 0.9054054 0.5185185
|
||||
127424481939351r140737488355328 1037037r2000000
|
||||
x: 0.9054054054 0.5185185185
|
||||
5358191125333r5918002138463 6073341499873r11712872893031
|
||||
x: 0.9054054054054 0.5185185185185
|
||||
67r74 14r27
|
||||
x: 0.9054054054054054 0.5185185185185185
|
||||
67r74 14r27
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
x:(!. 5e_11) 0.9054054054 0.5185185185
|
||||
67r74 14r27
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
0j10": x:inv x: 0.9054054 0.518518 0.75 NB. invertible (shown to 10 decimal places)
|
||||
0.9054054000 0.5185180000 0.7500000000
|
||||
0j10": x:inv 67r74 42r81 3r4 NB. decimal representation (shown to 10 decimal places)
|
||||
0.9054054054 0.5185185185 0.7500000000
|
||||
x: x:inv 67r74 42r81 3r4 NB. invertible
|
||||
67r74 14r27 3r4
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
double fractionToDecimal(String string) {
|
||||
int indexOf = string.indexOf(' ');
|
||||
int integer = 0;
|
||||
int numerator, denominator;
|
||||
if (indexOf != -1) {
|
||||
integer = Integer.parseInt(string.substring(0, indexOf));
|
||||
string = string.substring(indexOf + 1);
|
||||
}
|
||||
indexOf = string.indexOf('/');
|
||||
numerator = Integer.parseInt(string.substring(0, indexOf));
|
||||
denominator = Integer.parseInt(string.substring(indexOf + 1));
|
||||
return integer + ((double) numerator / denominator);
|
||||
}
|
||||
|
||||
String decimalToFraction(double value) {
|
||||
String string = String.valueOf(value);
|
||||
string = string.substring(string.indexOf('.') + 1);
|
||||
int numerator = Integer.parseInt(string);
|
||||
int denominator = (int) Math.pow(10, string.length());
|
||||
int gcf = gcf(numerator, denominator);
|
||||
if (gcf != 0) {
|
||||
numerator /= gcf;
|
||||
denominator /= gcf;
|
||||
}
|
||||
int integer = (int) value;
|
||||
if (integer != 0)
|
||||
return "%d %d/%d".formatted(integer, numerator, denominator);
|
||||
return "%d/%d".formatted(numerator, denominator);
|
||||
}
|
||||
|
||||
int gcf(int valueA, int valueB) {
|
||||
if (valueB == 0) return valueA;
|
||||
else return gcf(valueB, valueA % valueB);
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
import org.apache.commons.math3.fraction.BigFraction;
|
||||
|
||||
public class Test {
|
||||
|
||||
public static void main(String[] args) {
|
||||
double[] n = {0.750000000, 0.518518000, 0.905405400, 0.142857143,
|
||||
3.141592654, 2.718281828, -0.423310825, 31.415926536};
|
||||
|
||||
for (double d : n)
|
||||
System.out.printf("%-12s : %s%n", d, new BigFraction(d, 0.00000002D, 10000));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
(() => {
|
||||
'use strict';
|
||||
|
||||
const main = () =>
|
||||
showJSON(
|
||||
map( // Using a tolerance epsilon of 1/10000
|
||||
n => showRatio(approxRatio(0.0001)(n)),
|
||||
[0.9054054, 0.518518, 0.75]
|
||||
)
|
||||
);
|
||||
|
||||
// Epsilon -> Real -> Ratio
|
||||
|
||||
// approxRatio :: Real -> Real -> Ratio
|
||||
const approxRatio = eps => n => {
|
||||
const
|
||||
gcde = (e, x, y) => {
|
||||
const _gcd = (a, b) => (b < e ? a : _gcd(b, a % b));
|
||||
return _gcd(Math.abs(x), Math.abs(y));
|
||||
},
|
||||
c = gcde(Boolean(eps) ? eps : (1 / 10000), 1, n);
|
||||
return Ratio(
|
||||
Math.floor(n / c), // numerator
|
||||
Math.floor(1 / c) // denominator
|
||||
);
|
||||
};
|
||||
|
||||
// GENERIC FUNCTIONS ----------------------------------
|
||||
|
||||
// Ratio :: Int -> Int -> Ratio
|
||||
const Ratio = (n, d) => ({
|
||||
type: 'Ratio',
|
||||
'n': n, // numerator
|
||||
'd': d // denominator
|
||||
});
|
||||
|
||||
// map :: (a -> b) -> [a] -> [b]
|
||||
const map = (f, xs) => xs.map(f);
|
||||
|
||||
// showJSON :: a -> String
|
||||
const showJSON = x => JSON.stringify(x, null, 2);
|
||||
|
||||
// showRatio :: Ratio -> String
|
||||
const showRatio = nd =>
|
||||
nd.n.toString() + '/' + nd.d.toString();
|
||||
|
||||
// MAIN ---
|
||||
return main();
|
||||
})();
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
# include "rational"; # a reminder that r/2 and power/1 are required
|
||||
|
||||
# Input: any JSON number, not only a decimal
|
||||
# Output: a rational, constructed using r/2
|
||||
# Requires power/1 (to take advantage of gojq's support for integer arithmetic)
|
||||
# and r/2 (for rational number constructor)
|
||||
def number_to_r:
|
||||
|
||||
# input: a decimal string
|
||||
# $in - either null or the original input
|
||||
# $e - the integer exponent of the original number, or 0
|
||||
def dtor($in; $e):
|
||||
index(".") as $ix
|
||||
| if $in and ($ix == null) then $in
|
||||
else (if $ix then sub("[.]"; "") else . end | tonumber) as $n
|
||||
| (if $ix then ((length - ($ix+1)) - $e) else - $e end) as $p
|
||||
| if $p >= 0
|
||||
then r( $n; 10|power($p))
|
||||
else r( $n * (10|power(-$p)); 1)
|
||||
end
|
||||
end;
|
||||
|
||||
. as $in
|
||||
| tostring
|
||||
| if (test("[Ee]")|not) then dtor($in; 0)
|
||||
else capture("^(?<s>[^eE]*)[Ee](?<e>.*$)")
|
||||
| (.e | if length > 0 then tonumber else 0 end) as $e
|
||||
| .s | dtor(null; $e)
|
||||
end ;
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
0.9054054,
|
||||
0.518518,
|
||||
0.75,
|
||||
1e308
|
||||
| "\(.) → \(number_to_r | rpp)"
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
rationalize(0.9054054)
|
||||
rationalize(0.518518)
|
||||
rationalize(0.75)
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
function rat(x::AbstractFloat, tol::Real=eps(x))::Rational
|
||||
p, q, pp, qq = copysign(1,x), 0, 0, 1
|
||||
x, y = abs(x), 1.0
|
||||
r, a = modf(x)
|
||||
nt, t, tt = tol, 0.0, tol
|
||||
|
||||
while r > nt # convergents of the continued fraction: np//nq = (p*a + pp) // (q*a + qq)
|
||||
np, nq = Int(a).*(p,q) .+ (pp,qq)
|
||||
p, pp, q, qq = np, p, nq, q
|
||||
|
||||
x, y = y, r # instead of the inexact 1/r...
|
||||
a, r = divrem(x,y)
|
||||
|
||||
t, tt = nt, t # maintain x = (p + (-1)^i * r) / q
|
||||
nt = a*t+tt
|
||||
end
|
||||
|
||||
i = Int(cld(x-tt,y+t)) # find optimal semiconvergent: smallest i such that x-i*y < i*t+tt
|
||||
return (i*p+pp) // (i*q+qq)
|
||||
end
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
// version 1.1.2
|
||||
|
||||
class Rational(val num: Long, val den: Long) {
|
||||
override fun toString() = "$num/$den"
|
||||
}
|
||||
|
||||
fun decimalToRational(d: Double): Rational {
|
||||
val ds = d.toString().trimEnd('0').trimEnd('.')
|
||||
val index = ds.indexOf('.')
|
||||
if (index == -1) return Rational(ds.toLong(), 1L)
|
||||
var num = ds.replace(".", "").toLong()
|
||||
var den = 1L
|
||||
for (n in 1..(ds.length - index - 1)) den *= 10L
|
||||
while (num % 2L == 0L && den % 2L == 0L) {
|
||||
num /= 2L
|
||||
den /= 2L
|
||||
}
|
||||
while (num % 5L == 0L && den % 5L == 0L) {
|
||||
num /= 5L
|
||||
den /= 5L
|
||||
}
|
||||
return Rational(num, den)
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val decimals = doubleArrayOf(0.9054054, 0.518518, 2.405308, .75, 0.0, -0.64, 123.0, -14.6)
|
||||
for (decimal in decimals)
|
||||
println("${decimal.toString().padEnd(9)} = ${decimalToRational(decimal)}")
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
' Uses convention that one repeating sequence implies infinitely repeating sequence..
|
||||
' Non-recurring fractions are limited to nd number of digits in nuerator & denominator
|
||||
|
||||
nd =3 ' suggest 3. 4 is slow. >4 is .......
|
||||
do
|
||||
read x$
|
||||
data "0.5", "0.1", "0.333", "1 /3", "0.33", "0.14159265", "2^-0.5", "0.1 +0.9*rnd(1)"
|
||||
data "0.142857142857", "int( 1000*rnd(1))/int( 1000*rnd(1))","end" ' always between 0 and 0.999999...
|
||||
if x$ ="end" then exit do
|
||||
print x$; " is ";
|
||||
type$ =check$( x$)
|
||||
print type$;
|
||||
|
||||
if type$ ="recurring" then
|
||||
x =val( mid$( x$, 3, ( len( x$) -2) /2))
|
||||
rep =( len( x$) -2) /2
|
||||
num =x
|
||||
den =10^rep -1
|
||||
gcd =gcd( num, den)
|
||||
print
|
||||
print " Calculating exact fraction for ", recurring$( x); " recurring & found";
|
||||
print num /gcd; " /"; den /gcd
|
||||
print
|
||||
else ' non-recurring. Check numerators & denominators <1000
|
||||
x =eval( x$)
|
||||
print
|
||||
print " Looking for fractions that are close to "; using( "#.############", x); " & found ";
|
||||
eps =10^nd
|
||||
for n = 1 to nd
|
||||
for i =1 to 10^n -1
|
||||
for j =i to 10^n -1
|
||||
fr =i /j
|
||||
if abs( x -fr) <eps then
|
||||
eps =abs( x -fr)
|
||||
'print i; " /"; j; " = ", using( "##.############", fr), "with error +/-"; using( "###.#########", eps /x *100); " %"
|
||||
ii =i: jj =j
|
||||
if eps =0 then exit for
|
||||
end if
|
||||
next j
|
||||
scan
|
||||
if eps =0 then exit for
|
||||
next i
|
||||
if eps =0 then exit for
|
||||
next n
|
||||
print ii; " /"; jj
|
||||
print
|
||||
end if
|
||||
loop until 0
|
||||
|
||||
print
|
||||
print "END."
|
||||
|
||||
end
|
||||
|
||||
function recurring$( x)
|
||||
recurring$ ="0."
|
||||
do
|
||||
recurring$ =recurring$ +str$( x)
|
||||
loop until len( recurring$) >=14
|
||||
end function
|
||||
|
||||
function gcd( a, b) ' thanks Uncle Ben..
|
||||
while b <>0
|
||||
t =b
|
||||
b =a mod b
|
||||
a =t
|
||||
wend
|
||||
gcd =a
|
||||
end function
|
||||
|
||||
function check$( i$)
|
||||
check$ ="non-recurring"
|
||||
length =len( i$) -2 ' allow for the '0.'.
|
||||
if length /2 =int( length /2) then if mid$( i$, 3, length /2) =mid$( i$, 3 +length /2, length /2) then check$ ="recurring"
|
||||
end function
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
for _,v in ipairs({ 0.9054054, 0.518518, 0.75, math.pi }) do
|
||||
local n, d, dmax, eps = 1, 1, 1e7, 1e-15
|
||||
while math.abs(n/d-v)>eps and d<dmax do d=d+1 n=math.floor(v*d) end
|
||||
print(string.format("%15.13f --> %d / %d", v, n, d))
|
||||
end
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
module Convert_decimal_number_to_rational{
|
||||
Function Rational(numerator as decimal, denominator as decimal=1) {
|
||||
if denominator==0 then denominator=1
|
||||
while frac(numerator)<>0 {
|
||||
numerator*=10@
|
||||
denominator*=10@
|
||||
}
|
||||
sgn=Sgn(numerator)*Sgn(denominator)
|
||||
denominator<=abs(denominator)
|
||||
numerator<=abs(numerator)*sgn
|
||||
gcd1=lambda (a as decimal, b as decimal) -> {
|
||||
if a<b then swap a,b
|
||||
g=a mod b
|
||||
while g {a=b:b=g: g=a mod b}
|
||||
=abs(b)
|
||||
}
|
||||
gdcval=gcd1(abs(numerator), denominator)
|
||||
if gdcval<denominator and gdcval<>0 then
|
||||
denominator/=gdcval
|
||||
numerator/=gdcval
|
||||
end if
|
||||
=(numerator,denominator)
|
||||
}
|
||||
|
||||
Print Rational(0.9054054)#str$(" / ")="4527027 / 5000000" ' true
|
||||
Print Rational(0.518518)#str$(" / ")="259259 / 500000" ' true
|
||||
Print Rational(0.75)#str$(" / ")="3 / 4" ' true
|
||||
}
|
||||
Convert_decimal_number_to_rational
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
[a,b]=rat(.75)
|
||||
[a,b]=rat(.518518)
|
||||
[a,b]=rat(.9054054)
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
> map( convert, [ 0.9054054, 0.518518, 0.75 ], 'rational', 'exact' );
|
||||
4527027 259259
|
||||
[-------, ------, 3/4]
|
||||
5000000 500000
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
Map[Rationalize[#,0]&,{0.9054054,0.518518, 0.75} ]
|
||||
-> {4527027/5000000,259259/500000,3/4}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
/*NetRexx program to convert decimal numbers to fractions *************
|
||||
* 16.08.2012 Walter Pachl derived from Rexx Version 2
|
||||
**********************************************************************/
|
||||
options replace format comments java crossref savelog symbols
|
||||
Numeric Digits 10 /* use "only" 10 digs of precision */
|
||||
ratt('0.9054054054','67/74')
|
||||
ratt('0.5185185185','14/27')
|
||||
ratt('0.75' ,'3/4')
|
||||
ratt('0.905405400',' 693627417/766095958')
|
||||
ratt('0.9054054054','67/74')
|
||||
ratt('0.1428571428','1/7')
|
||||
ratt('35.000','35')
|
||||
ratt('35.001','35001/1000')
|
||||
ratt('0.00000000001','?')
|
||||
ratt('0.000001000001','1/999999')
|
||||
|
||||
ratt(0.9054054054,'1/3')
|
||||
|
||||
|
||||
method ratt(d = Rexx,fs = Rexx) public static
|
||||
fract=rat(d)
|
||||
Say ' 'd '->' fract
|
||||
Parse fract no '/' de
|
||||
If de='' Then x=no
|
||||
Else x=no/de
|
||||
If x<>d Then
|
||||
Say '> '||x 'is different'
|
||||
|
||||
method rat(in, high='') public static
|
||||
/**********************************************************************
|
||||
* rat(number<,high) returns a fraction or an integer that is equal to
|
||||
* or approximately equal to number.
|
||||
* Nominator and denominator must not have more than high digits
|
||||
* 16.08.2012 Walter Pachl derived from Rexx Version 2
|
||||
**********************************************************************/
|
||||
if high=='' then
|
||||
high=10**(digits - 1) /* maximum nominator/denominator */
|
||||
x=in /* working copy */
|
||||
nom=0 /* start values nominator */
|
||||
den=1 /* denominator */
|
||||
tnom=1 /* temp nominator */
|
||||
tden=0 /* temp denominator */
|
||||
loop While tnom<=high & tden<=high /* nominator... not too large */
|
||||
n=x.trunc() /* take integer part of x */
|
||||
z=tnom; /* save temp nominator */
|
||||
tnom=n*tnom+nom; /* compute new temp nominator */
|
||||
nom=z /* assign nominator */
|
||||
z=tden; /* save temp denominator */
|
||||
tden=n*tden+den /* compute new temp denominato*/
|
||||
den=z /* assign denominator */
|
||||
if n=x | tnom/tden=in then do
|
||||
if tnom>high | tden>high then /* temp value(s) too large */
|
||||
Leave /* don't use them */
|
||||
nom=tnom /* otherwise take them as */
|
||||
den=tden /* final values */
|
||||
leave /* and end the loop */
|
||||
end
|
||||
x=1/(x-n) /* compute x for next round */
|
||||
end
|
||||
If den=1 Then Return nom /* an integer */
|
||||
Else Return nom'/'den /* otherwise a fraction */
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
import math
|
||||
import fenv
|
||||
|
||||
type
|
||||
Rational = object
|
||||
numerator: int
|
||||
denominator: int
|
||||
|
||||
proc `$`(self: Rational): string =
|
||||
if self.denominator == 1:
|
||||
$self.numerator
|
||||
else:
|
||||
$self.numerator & "//" & $self.denominator
|
||||
|
||||
func rationalize(x: float, tol: float = epsilon(float)): Rational =
|
||||
var xx = x
|
||||
let flagNeg = xx < 0.0
|
||||
if flagNeg:
|
||||
xx = -xx
|
||||
if xx < minimumPositiveValue(float):
|
||||
return Rational(numerator: 0, denominator: 1)
|
||||
if abs(xx - round(xx)) < tol:
|
||||
return Rational(numerator: int(round(xx)), denominator: 1)
|
||||
var a = 0
|
||||
var b = 1
|
||||
var c = int(ceil(xx))
|
||||
var d = 1
|
||||
var aux1 = high(int) div 2
|
||||
while c < aux1 and d < aux1:
|
||||
var aux2 = (float(a) + float(c)) / (float(b) + float(d))
|
||||
if abs(xx - aux2) < tol:
|
||||
break
|
||||
if xx > aux2:
|
||||
inc a, c
|
||||
inc b, d
|
||||
else:
|
||||
inc c, a
|
||||
inc d, b
|
||||
var gcd = gcd(a + c, b + d)
|
||||
if flagNeg:
|
||||
Rational(numerator: -(a + c) div gcd, denominator: (b + d) div gcd)
|
||||
else:
|
||||
Rational(numerator: (a + c) div gcd, denominator: (b + d) div gcd)
|
||||
|
||||
echo rationalize(0.9054054054)
|
||||
echo rationalize(0.9054054054, 0.0001)
|
||||
echo rationalize(0.5185185185)
|
||||
echo rationalize(0.5185185185, 0.0001)
|
||||
echo rationalize(0.75)
|
||||
echo rationalize(0.1428571428, 0.001)
|
||||
echo rationalize(35.000)
|
||||
echo rationalize(35.001)
|
||||
echo rationalize(0.9)
|
||||
echo rationalize(0.99)
|
||||
echo rationalize(0.909)
|
||||
echo rationalize(0.909, 0.001)
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
import rationals
|
||||
|
||||
echo toRational(0.9054054054)
|
||||
echo toRational(0.5185185185)
|
||||
echo toRational(0.75)
|
||||
echo toRational(0.1428571428)
|
||||
echo toRational(35.000)
|
||||
echo toRational(35.001)
|
||||
echo toRational(0.9)
|
||||
echo toRational(0.99)
|
||||
echo toRational(0.909)
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
convert(x)={
|
||||
my(n=0);
|
||||
while(x-floor(x*10^n)/10^n!=0.,n++);
|
||||
floor(x*10^n)/10^n
|
||||
};
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
function asRational($val, $tolerance = 1.e-6)
|
||||
{
|
||||
if ($val == (int) $val) {
|
||||
// integer
|
||||
return $val;
|
||||
}
|
||||
|
||||
$h1=1;
|
||||
$h2=0;
|
||||
$k1=0;
|
||||
$k2=1;
|
||||
$b = 1 / $val;
|
||||
|
||||
do {
|
||||
$b = 1 / $b;
|
||||
$a = floor($b);
|
||||
$aux = $h1;
|
||||
$h1 = $a * $h1 + $h2;
|
||||
$h2 = $aux;
|
||||
$aux = $k1;
|
||||
$k1 = $a * $k1 + $k2;
|
||||
$k2 = $aux;
|
||||
$b = $b - $a;
|
||||
} while (abs($val-$h1/$k1) > $val * $tolerance);
|
||||
|
||||
return $h1.'/'.$k1;
|
||||
}
|
||||
|
||||
echo asRational(1/5)."\n"; // "1/5"
|
||||
echo asRational(1/4)."\n"; // "1/4"
|
||||
echo asRational(1/3)."\n"; // "1/3"
|
||||
echo asRational(5)."\n"; // "5"
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
(size, fofl):
|
||||
Convert_Decimal_To_Rational: procedure options (main); /* 14 January 2014, from Ada */
|
||||
|
||||
Real_To_Rational: procedure (R, Bound, Numerator, Denominator) recursive
|
||||
options (reorder);
|
||||
declare R float (18), Bound float,
|
||||
(Numerator, Denominator) fixed binary (31);
|
||||
declare Error float;
|
||||
declare Best fixed binary initial (1);
|
||||
declare Best_Error float initial (huge(error));
|
||||
declare I fixed binary (31);
|
||||
|
||||
if R = 0 then
|
||||
do;
|
||||
Numerator = 0;
|
||||
Denominator = 1;
|
||||
return;
|
||||
end;
|
||||
else if R < 0 then
|
||||
do;
|
||||
call Real_To_Rational(-R, Bound, Numerator, Denominator);
|
||||
Numerator = -Numerator;
|
||||
return;
|
||||
end;
|
||||
else
|
||||
do I = 1 to Bound;
|
||||
Error = abs(I * R - trunc(I * R + sign(R)*0.5));
|
||||
if Error < Best_Error then
|
||||
do;
|
||||
Best = I;
|
||||
Best_Error = Error;
|
||||
end;
|
||||
end;
|
||||
|
||||
Denominator = Best;
|
||||
Numerator = Denominator * R + sign(R) * 0.5;
|
||||
|
||||
end Real_To_Rational;
|
||||
|
||||
|
||||
declare (Num, Denom) fixed binary (31);
|
||||
declare R float (18);
|
||||
declare I fixed BINARY;
|
||||
|
||||
do R = 0.75, 0.25, 0.3333333, 0.518518000, 0.905405400,
|
||||
0.142857143, 3.141592654, 2.718281828, -0.423310825,
|
||||
31.415926536, 0;
|
||||
put skip edit(R) (f(13,9));
|
||||
do I = 0 to 4;
|
||||
call Real_to_Rational(R, 10**I, Num, Denom);
|
||||
put edit(' ' || trim(Num) || ' / ' || trim(Denom)) (a);
|
||||
end;
|
||||
end;
|
||||
end Convert_Decimal_To_Rational;
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
sub gcd {
|
||||
my ($m, $n) = @_;
|
||||
($m, $n) = ($n, $m % $n) while $n;
|
||||
return $m
|
||||
}
|
||||
|
||||
sub rat_machine {
|
||||
my $n = shift;
|
||||
my $denom = 1;
|
||||
while ($n != int $n) {
|
||||
# assuming the machine format is base 2, and multiplying
|
||||
# by 2 doesn't change the mantissa
|
||||
$n *= 2;
|
||||
|
||||
# multiply denom by 2, ignoring (very) possible overflow
|
||||
$denom <<= 1;
|
||||
}
|
||||
if ($n) {
|
||||
my $g = gcd($n, $denom);
|
||||
$n /= $g;
|
||||
$denom /= $g;
|
||||
}
|
||||
return $n, $denom;
|
||||
}
|
||||
|
||||
# helper, make continued fraction back into normal fraction
|
||||
sub get_denom {
|
||||
my ($num, $denom) = (1, pop @_);
|
||||
for (reverse @_) {
|
||||
($num, $denom) = ($denom, $_ * $denom + $num);
|
||||
}
|
||||
wantarray ? ($num, $denom) : $denom
|
||||
}
|
||||
|
||||
sub best_approx {
|
||||
my ($n, $limit) = @_;
|
||||
my ($denom, $neg);
|
||||
if ($n < 0) {
|
||||
$neg = 1;
|
||||
$n = -$n;
|
||||
}
|
||||
|
||||
my $int = int($n);
|
||||
my ($num, $denom, @coef) = (1, $n - $int);
|
||||
|
||||
# continued fraction, sort of
|
||||
while (1) {
|
||||
# make sure it terminates
|
||||
last if $limit * $denom < 1;
|
||||
my $i = int($num / $denom);
|
||||
|
||||
# not the right way to get limit, but it works
|
||||
push @coef, $i;
|
||||
|
||||
if (get_denom(@coef) > $limit) {
|
||||
pop @coef;
|
||||
last;
|
||||
}
|
||||
|
||||
# we lose precision here, but c'est la vie
|
||||
($num, $denom) = ($denom, $num - $i * $denom);
|
||||
}
|
||||
|
||||
($num, $denom) = get_denom @coef;
|
||||
$num += $denom * $int;
|
||||
|
||||
return $neg ? -$num : $num, $denom;
|
||||
}
|
||||
|
||||
sub rat_string {
|
||||
my $n = shift;
|
||||
my $denom = 1;
|
||||
my $neg;
|
||||
|
||||
# trival xyz.0000 ... case
|
||||
$n =~ s/\.0+$//;
|
||||
return $n, 1 unless $n =~ /\./;
|
||||
|
||||
if ($n =~ /^-/) {
|
||||
$neg = 1;
|
||||
$n =~ s/^-//;
|
||||
}
|
||||
|
||||
# shift decimal point to the right till it's gone
|
||||
$denom *= 10 while $n =~ s/\.(\d)/$1\./;
|
||||
$n =~ s/\.$//;
|
||||
|
||||
# removing leading zeros lest it looks like octal
|
||||
$n =~ s/^0*//;
|
||||
if ($n) {
|
||||
my $g = gcd($n, $denom);
|
||||
$n /= $g;
|
||||
$denom /= $g;
|
||||
}
|
||||
return $neg ? -$n : $n, $denom;
|
||||
}
|
||||
|
||||
my $limit = 1e8;
|
||||
my $x = 3/8;
|
||||
print "3/8 = $x:\n";
|
||||
printf "machine: %d/%d\n", rat_machine $x;
|
||||
printf "string: %d/%d\n", rat_string $x;
|
||||
printf "approx below $limit: %d/%d\n", best_approx $x, $limit;
|
||||
|
||||
$x = 137/4291;
|
||||
print "\n137/4291 = $x:\n";
|
||||
printf "machine: %d/%d\n", rat_machine $x;
|
||||
printf "string: %d/%d\n", rat_string $x;
|
||||
printf "approx below $limit: %d/%d\n", best_approx $x, $limit;
|
||||
|
||||
$x = sqrt(1/2);
|
||||
print "\n1/sqrt(2) = $x\n";
|
||||
printf "machine: %d/%d\n", rat_machine $x;
|
||||
printf "string: %d/%d\n", rat_string $x;
|
||||
printf "approx below 10: %d/%d\n", best_approx $x, 10;
|
||||
printf "approx below 100: %d/%d\n", best_approx $x, 100;
|
||||
printf "approx below 1000: %d/%d\n", best_approx $x, 1000;
|
||||
printf "approx below 10000: %d/%d\n", best_approx $x, 10000;
|
||||
printf "approx below 100000: %d/%d\n", best_approx $x, 100000;
|
||||
printf "approx below $limit: %d/%d\n", best_approx $x, $limit;
|
||||
|
||||
$x = -4 * atan2(1,1);
|
||||
print "\n-Pi = $x\n";
|
||||
printf "machine: %d/%d\n", rat_machine $x;
|
||||
printf "string: %d/%d\n", rat_string $x;
|
||||
|
||||
for (map { 10 ** $_ } 1 .. 10) {
|
||||
printf "approx below %g: %d / %d\n", $_, best_approx($x, $_)
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
(phixonline)-->
|
||||
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
|
||||
<span style="color: #008080;">function</span> <span style="color: #000000;">decrat</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #004080;">integer</span> <span style="color: #000000;">nom</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span>
|
||||
<span style="color: #000000;">denom</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
|
||||
<span style="color: #7060A8;">assert</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..</span><span style="color: #000000;">2</span><span style="color: #0000FF;">]=</span><span style="color: #008000;">"0."</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">3</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #004080;">integer</span> <span style="color: #000000;">ch</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
|
||||
<span style="color: #7060A8;">assert</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ch</span><span style="color: #0000FF;">>=</span><span style="color: #008000;">'0'</span> <span style="color: #008080;">and</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;"><=</span><span style="color: #008000;">'9'</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">nom</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">nom</span><span style="color: #0000FF;">*</span><span style="color: #000000;">10</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;">-</span><span style="color: #008000;">'0'</span>
|
||||
<span style="color: #000000;">denom</span> <span style="color: #0000FF;">*=</span> <span style="color: #000000;">10</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
|
||||
<span style="color: #008080;">return</span> <span style="color: #7060A8;">sq_div</span><span style="color: #0000FF;">({</span><span style="color: #000000;">nom</span><span style="color: #0000FF;">,</span><span style="color: #000000;">denom</span><span style="color: #0000FF;">},</span><span style="color: #7060A8;">gcd</span><span style="color: #0000FF;">(</span><span style="color: #000000;">nom</span><span style="color: #0000FF;">,</span><span style="color: #000000;">denom</span><span style="color: #0000FF;">))</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
|
||||
|
||||
<span style="color: #0000FF;">?</span><span style="color: #000000;">decrat</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"0.9054054"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #0000FF;">?</span><span style="color: #000000;">decrat</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"0.518518"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #0000FF;">?</span><span style="color: #000000;">decrat</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"0.75"</span><span style="color: #0000FF;">)</span>
|
||||
<!--
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
Procedure.i ggT(a.i, b.i)
|
||||
Define t.i : If a < b : Swap a, b : EndIf
|
||||
While a%b : t=a : a=b : b=t%a : Wend : ProcedureReturn b
|
||||
EndProcedure
|
||||
|
||||
Procedure.s Dec2Rat(dn.d)
|
||||
Define nk$, gt.i, res$
|
||||
nk$=Trim(StringField(StrD(dn),2,"."),"0")
|
||||
gt=ggT(Val(nk$),Int(Pow(10.0,Len(nk$))))
|
||||
res$=Str(Val(nk$)/gt)+"/"+Str(Int(Pow(10.0,Len(nk$)))/gt)
|
||||
ProcedureReturn res$
|
||||
EndProcedure
|
||||
|
||||
OpenConsole()
|
||||
Define d.d
|
||||
Repeat
|
||||
Read.d d : If Not (d>0.0 And d<1.0) : Break : EndIf
|
||||
Print(LSet(StrD(d),15," ")+" -> "+#TAB$+Dec2Rat(d)+#CRLF$)
|
||||
ForEver
|
||||
Input() : End
|
||||
|
||||
DataSection
|
||||
Data.d 0.9054054,0.518518,0.75,0.0
|
||||
EndDataSection
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
>>> from fractions import Fraction
|
||||
>>> for d in (0.9054054, 0.518518, 0.75): print(d, Fraction.from_float(d).limit_denominator(100))
|
||||
|
||||
0.9054054 67/74
|
||||
0.518518 14/27
|
||||
0.75 3/4
|
||||
>>> for d in '0.9054054 0.518518 0.75'.split(): print(d, Fraction(d))
|
||||
|
||||
0.9054054 4527027/5000000
|
||||
0.518518 259259/500000
|
||||
0.75 3/4
|
||||
>>>
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
'''Approximate rationals from decimals'''
|
||||
|
||||
from math import (floor, gcd)
|
||||
import sys
|
||||
|
||||
|
||||
# approxRatio :: Float -> Float -> Ratio
|
||||
def approxRatio(epsilon):
|
||||
'''The simplest rational approximation to
|
||||
n within the margin given by epsilon.
|
||||
'''
|
||||
def gcde(e, x, y):
|
||||
def _gcd(a, b):
|
||||
return a if b < e else _gcd(b, a % b)
|
||||
return _gcd(abs(x), abs(y))
|
||||
return lambda n: (lambda c=(
|
||||
gcde(epsilon if 0 < epsilon else (0.0001), 1, n)
|
||||
): ratio(floor(n / c))(floor(1 / c)))()
|
||||
|
||||
|
||||
# main :: IO ()
|
||||
def main():
|
||||
'''Conversions at different levels of precision.'''
|
||||
|
||||
xs = [0.9054054, 0.518518, 0.75]
|
||||
print(
|
||||
fTable(__doc__ + ' (epsilon of 1/10000):\n')(str)(
|
||||
lambda r: showRatio(r) + ' -> ' + repr(fromRatio(r))
|
||||
)(
|
||||
approxRatio(1 / 10000)
|
||||
)(xs)
|
||||
)
|
||||
print('\n')
|
||||
|
||||
e = minBound(float)
|
||||
print(
|
||||
fTable(__doc__ + ' (epsilon of ' + repr(e) + '):\n')(str)(
|
||||
lambda r: showRatio(r) + ' -> ' + repr(fromRatio(r))
|
||||
)(
|
||||
approxRatio(e)
|
||||
)(xs)
|
||||
)
|
||||
|
||||
|
||||
# GENERIC -------------------------------------------------
|
||||
|
||||
# fromRatio :: Ratio Int -> Float
|
||||
def fromRatio(r):
|
||||
'''A floating point value derived from a
|
||||
a rational value.
|
||||
'''
|
||||
return r.get('numerator') / r.get('denominator')
|
||||
|
||||
|
||||
# minBound :: Bounded Type -> a
|
||||
def minBound(t):
|
||||
'''Minimum value for a bounded type.'''
|
||||
maxsize = sys.maxsize
|
||||
float_infomin = sys.float_info.min
|
||||
return {
|
||||
int: (-maxsize - 1),
|
||||
float: float_infomin,
|
||||
bool: False,
|
||||
str: chr(0)
|
||||
}[t]
|
||||
|
||||
|
||||
# ratio :: Int -> Int -> Ratio Int
|
||||
def ratio(n):
|
||||
'''Rational value constructed
|
||||
from a numerator and a denominator.
|
||||
'''
|
||||
def go(n, d):
|
||||
g = gcd(n, d)
|
||||
return {
|
||||
'type': 'Ratio',
|
||||
'numerator': n // g, 'denominator': d // g
|
||||
}
|
||||
return lambda d: go(n * signum(d), abs(d))
|
||||
|
||||
|
||||
# showRatio :: Ratio -> String
|
||||
def showRatio(r):
|
||||
'''String representation of the ratio r.'''
|
||||
d = r.get('denominator')
|
||||
return str(r.get('numerator')) + (
|
||||
' / ' + str(d) if 1 != d else ''
|
||||
)
|
||||
|
||||
|
||||
# signum :: Num -> Num
|
||||
def signum(n):
|
||||
'''The sign of n.'''
|
||||
return -1 if 0 > n else (1 if 0 < n else 0)
|
||||
|
||||
|
||||
# DISPLAY -------------------------------------------------
|
||||
|
||||
# fTable :: String -> (a -> String) ->
|
||||
# (b -> String) -> (a -> b) -> [a] -> String
|
||||
def fTable(s):
|
||||
'''Heading -> x display function -> fx display function ->
|
||||
f -> xs -> tabular string.
|
||||
'''
|
||||
def go(xShow, fxShow, f, xs):
|
||||
ys = [xShow(x) for x in xs]
|
||||
w = max(map(len, ys))
|
||||
return s + '\n' + '\n'.join(map(
|
||||
lambda x, y: y.rjust(w, ' ') + ' -> ' + fxShow(f(x)),
|
||||
xs, ys
|
||||
))
|
||||
return lambda xShow: lambda fxShow: lambda f: lambda xs: go(
|
||||
xShow, fxShow, f, xs
|
||||
)
|
||||
|
||||
|
||||
# MAIN ---
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
[ $ "bigrat.qky" loadfile ] now!
|
||||
|
||||
[ dup echo$
|
||||
say " is "
|
||||
$->v drop
|
||||
dup 100 > if
|
||||
[ say "approximately "
|
||||
proper 100 round
|
||||
improper ]
|
||||
vulgar$ echo$
|
||||
say "." cr ] is task ( $ --> )
|
||||
|
||||
$ "0.9054054 0.518518 0.75" nest$ witheach task
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
ratio<-function(decimal){
|
||||
denominator=1
|
||||
while(nchar(decimal*denominator)!=nchar(round(decimal*denominator))){
|
||||
denominator=denominator+1
|
||||
}
|
||||
str=paste(decimal*denominator,"/",sep="")
|
||||
str=paste(str,denominator,sep="")
|
||||
return(str)
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
/*REXX program converts a rational fraction [n/m] (or nnn.ddd) to it's lowest terms.*/
|
||||
numeric digits 10 /*use ten decimal digits of precision. */
|
||||
parse arg orig 1 n.1 "/" n.2; if n.2='' then n.2=1 /*get the fraction.*/
|
||||
if n.1='' then call er 'no argument specified.'
|
||||
|
||||
do j=1 for 2; if \datatype(n.j, 'N') then call er "argument isn't numeric:" n.j
|
||||
end /*j*/ /* [↑] validate arguments: n.1 n.2 */
|
||||
|
||||
if n.2=0 then call er "divisor can't be zero." /*Whoa! We're dividing by zero ! */
|
||||
say 'old =' space(orig) /*display the original fraction. */
|
||||
say 'new =' rat(n.1/n.2) /*display the result ──► terminal. */
|
||||
exit /*stick a fork in it, we're all done. */
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
er: say; say '***error***'; say; say arg(1); say; exit 13
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
rat: procedure; parse arg x 1 _x,y; if y=='' then y = 10**(digits()-1)
|
||||
b=0; g=0; a=1; h=1 /* [↑] Y is the tolerance.*/
|
||||
do while a<=y & g<=y; n=trunc(_x)
|
||||
_=a; a=n*a+b; b=_
|
||||
_=g; g=n*g+h; h=_
|
||||
if n=_x | a/g=x then do; if a>y | g>y then iterate
|
||||
b=a; h=g; leave
|
||||
end
|
||||
_x=1/(_x-n)
|
||||
end /*while*/
|
||||
if h==1 then return b /*don't return number ÷ by 1.*/
|
||||
return b'/'h /*proper or improper fraction. */
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
/*REXX program to convert decimal numbers to fractions ****************
|
||||
* 15.08.2012 Walter Pachl derived from above for readability
|
||||
* It took me time to understand :-) I need descriptive variable names
|
||||
* Output shows where the fraction only approximates the number
|
||||
* due to the limit (high) imposed on nominator and denominator
|
||||
**********************************************************************/
|
||||
Numeric Digits 10 /* use "only" 10 digs of precision */
|
||||
Call test '0.9054054054','67/74'
|
||||
Call test '0.5185185185','14/27'
|
||||
Call test '0.75' ,'3/4'
|
||||
Call test '0.905405400',' 693627417/766095958'
|
||||
Call test '0.9054054054','67/74'
|
||||
Call test '0.1428571428','1/7'
|
||||
Call test '35.000','35'
|
||||
Call test '35.001','35001/1000'
|
||||
Call test '0.00000000001','?'
|
||||
Call test '0.000001000001','1/999999'
|
||||
Exit
|
||||
|
||||
test:
|
||||
/**********************************************************************
|
||||
* Test driver for rat
|
||||
**********************************************************************/
|
||||
Parse Arg d,fs /* number and expected fraction */
|
||||
fh=rat(d) /* convert number to fracrion */
|
||||
Call o ' 'd fh
|
||||
If fh<>fs Then Call o ' not='fs
|
||||
interpret 'x='fh /* compute value of fraction */
|
||||
If x<>d Then /* not exactly equal to number */
|
||||
Call o '> '||x 'is different'
|
||||
Call o ' '
|
||||
Return
|
||||
|
||||
o: Say arg(1); Return
|
||||
|
||||
rat: procedure
|
||||
/**********************************************************************
|
||||
* rat(number<,high) returns a fraction or an integer that is equal to
|
||||
* or approximately equal to number.
|
||||
* Nominator and denominator must not have more than high digits
|
||||
* 15.08.2012 Walter Pachl derived from Version 1
|
||||
**********************************************************************/
|
||||
parse arg in,high
|
||||
x=in /* working copy */
|
||||
if high=='' then
|
||||
high=10**(digits()-1) /* maximum nominator/denominator */
|
||||
nom=0 /* start values nominator */
|
||||
den=1 /* denominator */
|
||||
tnom=1 /* temp nominator */
|
||||
tden=0 /* temp denominator */
|
||||
do While tnom<=high & tden<=high /* nominator... not too large */
|
||||
n=trunc(x) /* take integer part of x */
|
||||
z=tnom; /* save temp nominator */
|
||||
tnom=n*tnom+nom; /* compute new temp nominator */
|
||||
nom=z /* assign nominator */
|
||||
z=tden; /* save temp denominator */
|
||||
tden=n*tden+den /* compute new temp denominato*/
|
||||
den=z /* assign denominator */
|
||||
if n=x | tnom/tden=in then do
|
||||
if tnom>high | tden>high then /* temp value(s) too large */
|
||||
Leave /* don't use them */
|
||||
nom=tnom /* otherwise take them as */
|
||||
den=tden /* final values */
|
||||
leave /* and end the loop */
|
||||
end
|
||||
x=1/(x-n) /* compute x for next round */
|
||||
end
|
||||
if den=1 then return nom /* denominator 1: integer */
|
||||
return nom'/'den /* otherwise a fraction */
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
/* REXX ---------------------------------------------------------------
|
||||
* 13.02.2014 Walter Pachl
|
||||
* specify the number as xxx.yyy(pqr) pqr is the period
|
||||
* for the number xxx.yyypqrpqrpqrpqrpqr...
|
||||
*--------------------------------------------------------------------*/
|
||||
Numeric Digits 100
|
||||
Call test '5.55555','111111/20000'
|
||||
Call test '3','3'
|
||||
Call test '0.03','3/100'
|
||||
Call test '0.9(054)','67/74'
|
||||
Call test '0.(3)','1/3'
|
||||
Call test '5.28(571428)','37/7'
|
||||
Call test '5.28(571428)','38/7 (demonstrate error case)'
|
||||
Call test '0.(518)','14/27'
|
||||
Call test '0.75' ,'3/4'
|
||||
Call test '0.(142857)','1/7'
|
||||
Call test '0.1(428571)','1/7'
|
||||
Call test '35.000','35'
|
||||
Call test '35.001','35001/1000'
|
||||
Call test '0.00000000001','1/100000000000'
|
||||
Call test '0.000001000001','1000001/1000000000000'
|
||||
Exit
|
||||
test:
|
||||
Parse Arg z, soll
|
||||
zin=z
|
||||
If pos('(',z)=0 Then Do
|
||||
Parse Var z i '.' f
|
||||
z=i||f
|
||||
n=10**length(f)
|
||||
End
|
||||
Else Do
|
||||
lp=pos('(',z)-3
|
||||
rp=pos(')',z)-4
|
||||
x=space(translate(z,' ','()'),0)
|
||||
z1=x*10**lp
|
||||
Parse Var z1 z1 '.'
|
||||
z2=x*10**rp
|
||||
z=z2-z1
|
||||
n=10**rp-10**lp
|
||||
End
|
||||
dd=gcd(z,n)
|
||||
zz=z/dd
|
||||
nn=n/dd
|
||||
If nn=1 Then
|
||||
fract=zz
|
||||
Else
|
||||
fract=zz'/'nn
|
||||
If fract==soll Then
|
||||
tag='ok'
|
||||
Else
|
||||
tag='should be' soll
|
||||
say zin '=' fract tag
|
||||
Return
|
||||
|
||||
GCD: procedure
|
||||
/**********************************************************************
|
||||
* Recursive procedure
|
||||
**********************************************************************/
|
||||
Parse Arg a,b
|
||||
if b = 0 then return abs(a)
|
||||
return GCD(b,a//b)
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
#lang racket
|
||||
|
||||
(inexact->exact 0.75) ; -> 3/4
|
||||
(exact->inexact 3/4) ; -> 0.75
|
||||
|
||||
(exact->inexact 67/74) ; -> 0.9054054054054054
|
||||
(inexact->exact 0.9054054054054054) ;-> 8155166892806033/9007199254740992
|
||||
|
|
@ -0,0 +1 @@
|
|||
say .nude.join('/') for 0.9054054, 0.518518, 0.75;
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
sub decimal_to_fraction ( Str $n, Int $rep_digits = 0 ) returns Str {
|
||||
my ( $int, $dec ) = ( $n ~~ /^ (\d+) \. (\d+) $/ )».Str or die;
|
||||
|
||||
my ( $numer, $denom ) = ( $dec, 10 ** $dec.chars );
|
||||
if $rep_digits {
|
||||
my $to_move = $dec.chars - $rep_digits;
|
||||
$numer -= $dec.substr(0, $to_move);
|
||||
$denom -= 10 ** $to_move;
|
||||
}
|
||||
|
||||
my $rat = Rat.new( $numer.Int, $denom.Int ).nude.join('/');
|
||||
return $int > 0 ?? "$int $rat" !! $rat;
|
||||
}
|
||||
|
||||
my @a = ['0.9054', 3], ['0.518', 3], ['0.75', 0], | (^4).map({['12.34567', $_]});
|
||||
for @a -> [ $n, $d ] {
|
||||
say "$n with $d repeating digits = ", decimal_to_fraction( $n, $d );
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
> '0.9054054 0.518518 0.75'.split.each { |d| puts "%s %s" % [d, Rational(d)] }
|
||||
0.9054054 4527027/5000000
|
||||
0.518518 259259/500000
|
||||
0.75 3/4
|
||||
=> ["0.9054054", "0.518518", "0.75"]
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
[0.9054054, 0.518518, 0.75].each { |f| puts "#{f} #{f.rationalize(0.0001)}" }
|
||||
# =>0.9054054 67/74
|
||||
# =>0.518518 14/27
|
||||
# =>0.75 3/4
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
extern crate rand;
|
||||
extern crate num;
|
||||
|
||||
use num::Integer;
|
||||
use rand::Rng;
|
||||
|
||||
fn decimal_to_rational (mut n : f64) -> [isize;2] {
|
||||
//Based on Farey sequences
|
||||
assert!(n.is_finite());
|
||||
let flag_neg = n < 0.0;
|
||||
if flag_neg { n = n*(-1.0) }
|
||||
if n < std::f64::MIN_POSITIVE { return [0,1] }
|
||||
if (n - n.round()).abs() < std::f64::EPSILON { return [n.round() as isize, 1] }
|
||||
let mut a : isize = 0;
|
||||
let mut b : isize = 1;
|
||||
let mut c : isize = n.ceil() as isize;
|
||||
let mut d : isize = 1;
|
||||
let aux1 = isize::max_value()/2;
|
||||
while c < aux1 && d < aux1 {
|
||||
let aux2 : f64 = (a as f64 + c as f64)/(b as f64 + d as f64);
|
||||
if (n - aux2).abs() < std::f64::EPSILON { break }
|
||||
if n > aux2 {
|
||||
a = a + c;
|
||||
b = b + d;
|
||||
} else {
|
||||
c = a + c;
|
||||
d = b + d;
|
||||
}
|
||||
}
|
||||
// Make sure that the fraction is irreducible
|
||||
let gcd = (a+c).gcd(&(b+d));
|
||||
if flag_neg { [-(a + c)/gcd, (b + d)/gcd] } else { [(a + c)/gcd, (b + d)/gcd] }
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test1 () {
|
||||
// Test the function with 1_000_000 random decimal numbers
|
||||
let mut rng = rand::thread_rng();
|
||||
for _i in 1..1_000_000 {
|
||||
let number = rng.gen::<f64>();
|
||||
let result = decimal_to_rational(number);
|
||||
assert!((number - (result[0] as f64)/(result[1] as f64)).abs() < std::f64::EPSILON);
|
||||
assert!(result[0].gcd(&result[1]) == 1);
|
||||
}
|
||||
}
|
||||
|
||||
fn main () {
|
||||
let mut rng = rand::thread_rng();
|
||||
for _i in 1..10 {
|
||||
let number = rng.gen::<f64>();
|
||||
let result = decimal_to_rational(number);
|
||||
if result[1] == 1 { println!("{} -> {}", number, result[0]) } else { println!("{} -> {}/{}", number, result[0], result[1]) }
|
||||
}
|
||||
for i in [-0.9054054, 0.518518, -0.75, 0.5185185185185185, -0.9054054054054054, 0.0, 1.0, 2.0].iter() {
|
||||
let result = decimal_to_rational(*i as f64);
|
||||
if result[1] == 1 { println!("{} = {}",*i, result[0]) } else { println!("{} = {}/{}", *i, result[0], result[1]) }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
import org.apache.commons.math3.fraction.BigFraction
|
||||
|
||||
object Number2Fraction extends App {
|
||||
val n = Array(0.750000000, 0.518518000, 0.905405400,
|
||||
0.142857143, 3.141592654, 2.718281828, -0.423310825, 31.415926536)
|
||||
for (d <- n)
|
||||
println(f"$d%-12s : ${new BigFraction(d, 0.00000002D, 10000)}%s")
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
$ include "seed7_05.s7i";
|
||||
include "bigrat.s7i";
|
||||
|
||||
const proc: main is func
|
||||
begin
|
||||
writeln(fraction(bigRational("0.9(054)")));
|
||||
writeln(fraction(bigRational("0.(518)")));
|
||||
writeln(fraction(bigRational("0.75")));
|
||||
writeln(fraction(bigRational("3.(142857)")));
|
||||
writeln(fraction(bigRational("0.(8867924528301)")));
|
||||
writeln(fraction(bigRational("0.(846153)")));
|
||||
writeln(fraction(bigRational("0.9054054")));
|
||||
writeln(fraction(bigRational("0.518518")));
|
||||
writeln(fraction(bigRational("0.14285714285714")));
|
||||
writeln(fraction(bigRational("3.14159265358979")));
|
||||
writeln(fraction(bigRational("2.718281828")));
|
||||
writeln(fraction(bigRational("31.415926536")));
|
||||
writeln(fraction(bigRational("0.000000000")));
|
||||
end func;
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
say 0.75.as_frac #=> 3/4
|
||||
say 0.518518.as_frac #=> 259259/500000
|
||||
say 0.9054054.as_frac #=> 4527027/5000000
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
'0.9054054 0.518518 0.75'.split.each { |str|
|
||||
say Num(str).as_frac
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
say 0.518518.rat_approx.as_frac #=> 14/27
|
||||
say 0.9054054.rat_approx.as_frac #=> 67/74
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
STO 0 // Decimal := User Input
|
||||
0 STO 1 // Denominator := 0
|
||||
*CP // RegT := 0
|
||||
1 SUM 1 // Denominator += 1
|
||||
RCL 1 * RCL 0 = Inv *Int // Find fractional part of Decimal * Denominator
|
||||
Inv *x=t 0 6 // If it is nonzero loop back to instruction 6
|
||||
RCL 1 x<>t // Report denominator
|
||||
RCL 0 * RCL 1 = // Report numerator
|
||||
R/S // End
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
#!/usr/bin/env tclsh
|
||||
|
||||
proc dbl2frac {dbl {eps 0.000001}} {
|
||||
for {set den 1} {$den<1024} {incr den} {
|
||||
set num [expr {round($dbl*$den)}]
|
||||
if {abs(double($num)/$den - $dbl) < $eps} break
|
||||
}
|
||||
list $num $den
|
||||
}
|
||||
#-------------------- That's all... the rest is the test suite
|
||||
if {[file tail $argv0] eq [file tail [info script]]} {
|
||||
foreach {test -> expected} {
|
||||
{dbl2frac 0.518518} -> {42 81}
|
||||
{dbl2frac 0.75} -> {3 4}
|
||||
{dbl2frac 0.9054054} -> {67 74}
|
||||
} {
|
||||
catch $test res
|
||||
if {$res ne $expected} {
|
||||
puts "$test -> $res, expected $expected"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
Function Real2Rational(r As Double, bound As Long) As String
|
||||
|
||||
If r = 0 Then
|
||||
Real2Rational = "0/1"
|
||||
ElseIf r < 0 Then
|
||||
Result = Real2Rational(-r, bound)
|
||||
Real2Rational = "-" & Result
|
||||
Else
|
||||
best = 1
|
||||
bestError = 1E+99
|
||||
For i = 1 To bound + 1
|
||||
currentError = Abs(i * r - Round(i * r))
|
||||
If currentError < bestError Then
|
||||
best = i
|
||||
bestError = currentError
|
||||
If bestError < 1 / bound Then GoTo SkipLoop
|
||||
End If
|
||||
Next i
|
||||
SkipLoop:
|
||||
Real2Rational = Round(best * r) & "/" & best
|
||||
End If
|
||||
End Function
|
||||
|
||||
Sub TestReal2Rational()
|
||||
Debug.Print "0.75" & ":";
|
||||
For i = 0 To 5
|
||||
Order = CDbl(10) ^ CDbl(i)
|
||||
Debug.Print " " & Real2Rational(0.75, CLng(Order));
|
||||
Next i
|
||||
Debug.Print
|
||||
|
||||
Debug.Print "0.518518" & ":";
|
||||
For i = 0 To 5
|
||||
Order = CDbl(10) ^ CDbl(i)
|
||||
Debug.Print " " & Real2Rational(0.518518, CLng(Order));
|
||||
Next i
|
||||
Debug.Print
|
||||
|
||||
Debug.Print "0.9054054" & ":";
|
||||
For i = 0 To 5
|
||||
Order = CDbl(10) ^ CDbl(i)
|
||||
Debug.Print " " & Real2Rational(0.9054054, CLng(Order));
|
||||
Next i
|
||||
Debug.Print
|
||||
|
||||
Debug.Print "0.142857143" & ":";
|
||||
For i = 0 To 5
|
||||
Order = CDbl(10) ^ CDbl(i)
|
||||
Debug.Print " " & Real2Rational(0.142857143, CLng(Order));
|
||||
Next i
|
||||
Debug.Print
|
||||
|
||||
Debug.Print "3.141592654" & ":";
|
||||
For i = 0 To 5
|
||||
Order = CDbl(10) ^ CDbl(i)
|
||||
Debug.Print " " & Real2Rational(3.141592654, CLng(Order));
|
||||
Next i
|
||||
Debug.Print
|
||||
|
||||
Debug.Print "2.718281828" & ":";
|
||||
For i = 0 To 5
|
||||
Order = CDbl(10) ^ CDbl(i)
|
||||
Debug.Print " " & Real2Rational(2.718281828, CLng(Order));
|
||||
Next i
|
||||
Debug.Print
|
||||
|
||||
Debug.Print "-0.423310825" & ":";
|
||||
For i = 0 To 5
|
||||
Order = CDbl(10) ^ CDbl(i)
|
||||
Debug.Print " " & Real2Rational(-0.423310825, CLng(Order));
|
||||
Next i
|
||||
Debug.Print
|
||||
|
||||
Debug.Print "31.415926536" & ":";
|
||||
For i = 0 To 5
|
||||
Order = CDbl(10) ^ CDbl(i)
|
||||
Debug.Print " " & Real2Rational(31.415926536, CLng(Order));
|
||||
Next i
|
||||
End Sub
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
struct Fraction {
|
||||
public long d;
|
||||
public long n;
|
||||
}
|
||||
|
||||
Fraction rat_approx(double f, long md) {
|
||||
long a;
|
||||
long[] h = {0, 1, 0};
|
||||
long[] k = {1, 0, 0};
|
||||
long x, d, n = 1;
|
||||
bool neg = false;
|
||||
if (md <= 1) return {1, (long)f};
|
||||
if (f < 0) {
|
||||
neg = true;
|
||||
f = -f;
|
||||
}
|
||||
while (f != Math.floor(f)) {
|
||||
n <<= 1;
|
||||
f *= 2;
|
||||
}
|
||||
d = (long)f;
|
||||
for (int i = 0; i < 64; i++) {
|
||||
a = (n != 0) ? d / n : 0;
|
||||
if (i != 0 && a == 0) break;
|
||||
x = d; d = n; n = x %n;
|
||||
x = a;
|
||||
if (k[1] * a + k[0] >= md) {
|
||||
x = (md - k[0]) / k[1];
|
||||
if (x * 2 >= a || k[1] >= md)
|
||||
i = 65;
|
||||
else
|
||||
break;
|
||||
}
|
||||
h[2] = x * h[1] + h[0]; h[0] = h[1]; h[1] = h[2];
|
||||
k[2] = x * k[1] + k[0]; k[0] = k[1]; k[1] = k[2];
|
||||
}
|
||||
return {k[1], neg ? -h[1] : h[1]};
|
||||
}
|
||||
|
||||
void main() {
|
||||
double f;
|
||||
|
||||
print("f = %16.14f\n", f = 1.0/7);
|
||||
for (int i = 1; i < 20000000; i *= 16) {
|
||||
print("denom <= %11d: ", i);
|
||||
var r = rat_approx(f, i);
|
||||
print("%11ld/%ld\n", r.n, r.d);
|
||||
}
|
||||
|
||||
print("f = %16.14f\n", f = Math.atan2(1,1) * 4);
|
||||
for (int i = 1; i < 20000000; i *= 16) {
|
||||
print("denom <= %11d: ", i);
|
||||
var r = rat_approx(f, i);
|
||||
print("%11ld/%ld\n", r.n, r.d);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
import "/rat" for Rat
|
||||
import "/fmt" for Fmt
|
||||
|
||||
var tests = [0.9054054, 0.518518, 0.75]
|
||||
for (test in tests) {
|
||||
var r = Rat.fromFloat(test)
|
||||
System.print("%(Fmt.s(-9, test)) -> %(r)")
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
fcn real2Rational(r,bound){
|
||||
if (r == 0.0) return(0,1);
|
||||
if (r < 0.0){
|
||||
result := real2Rational(-r, bound);
|
||||
return(-result[0],result[1]);
|
||||
} else {
|
||||
best,bestError := 1,(1.0).MAX;
|
||||
foreach i in ([1 .. bound + 1]){
|
||||
error := (r*i - (r*i).round()).abs();
|
||||
if (error < bestError) best,bestError = i,error;
|
||||
}
|
||||
return((r*best).round().toInt(),best);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
tests := T(0.750000000, 0.518518000, 0.905405400,
|
||||
0.142857143, 3.141592654, 2.718281828,
|
||||
-0.423310825, 31.415926536);
|
||||
foreach r in (tests) {
|
||||
print("%8.9f ".fmt(r));
|
||||
foreach i in (6)
|
||||
{ print(" %d/%d".fmt(real2Rational(r,(10).pow(i)).xplode())) }
|
||||
println();
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue