## digitalmars.D.bugs - [Issue 7885] New: std.rationals too

```http://d.puremagic.com/issues/show_bug.cgi?id=7885

Summary: std.rationals too
Product: D
Version: D2
Platform: All
OS/Version: All
Status: NEW
Severity: enhancement
Priority: P2
Component: Phobos
AssignedTo: nobody puremagic.com
ReportedBy: bearophile_hugs eml.cc

--- Comment #0 from bearophile_hugs eml.cc 2012-04-10 15:35:23 PDT ---
I suggest to add to Phobos rational numbers, based on BigInts.
A simple implementation from the RosettaCode site:
http://rosettacode.org/wiki/Arithmetic/Rational#D

import std.bigint, std.traits;

T gcd(T)(/*in*/ T a, /*in*/ T b) /*pure nothrow*/ {
// std.numeric.gcd doesn't work with BigInt
return (b != 0) ? gcd(b, a % b) : (a < 0) ? -a : a;
}

T lcm(T)(/*in*/ T a, /*in*/ T b) {
return a / gcd(a, b) * b;
}

BigInt toBig(T : BigInt)(/*const*/ ref T n) pure nothrow { return n; }

BigInt toBig(T)(const ref T n) pure nothrow if (isIntegral!T) {
return BigInt(n);
}

struct Rational {
/*const*/ private BigInt num, den; // numerator & denominator

private enum Type { NegINF = -2,
NegDEN = -1,
NaRAT  =  0,
NORMAL =  1,
PosINF =  2 };

this(U : Rational)(U n) pure nothrow {
num = n.num;
den = n.den;
}

this(U)(in U n) pure nothrow if (isIntegral!U) {
num = toBig(n);
den = 1UL;
}

this(U, V)(/*in*/ U n, /*in*/ V d) /*pure nothrow*/ {
num = toBig(n);
den = toBig(d);
/*const*/ BigInt common = gcd(num, den);
if (common != 0) {
num /= common;
den /= common;
} else { // infinite or NOT a Number
num = (num == 0) ? 0 : (num < 0) ? -1 : 1;
den = 0;
}
if (den < 0) { // assure den is non-negative
num = -num;
den = -den;
}
}

BigInt nomerator() /*const*/ pure nothrow  property {
return num;
}

BigInt denominator() /*const*/ pure nothrow  property {
return den;
}

string toString() /*const*/ {
if (den == 0) {
if (num == 0)
return "NaRat";
else
return ((num < 0) ? "-" : "+") ~ "infRat";
}
(den == 1 ? "" : ("/" ~ toDecimalString(den)));
}

Rational opBinary(string op)(/*in*/ Rational r)
/*const pure nothrow*/ if (op == "+" || op == "-") {
BigInt common = lcm(den, r.den);
BigInt n = mixin("common / den * num" ~ op ~
"common / r.den * r.num" );
return Rational(n, common);
}

Rational opBinary(string op)(/*in*/ Rational r)
/*const pure nothrow*/ if (op == "*") {
return Rational(num * r.num, den * r.den);
}

Rational opBinary(string op)(/*in*/ Rational r)
/*const pure nothrow*/ if (op == "/") {
return Rational(num * r.den, den * r.num);
}

Rational opBinary(string op, T)(in T r)
/*const pure nothrow*/ if (isIntegral!T && (op == "+" ||
op == "-" || op == "*" || op == "/")) {
return opBinary!op(Rational(r));
}

Rational opBinary(string op)(in size_t p)
/*const pure nothrow*/ if (op == "^^") {
return Rational(num ^^ p, den ^^ p);
}

Rational opBinaryRight(string op, T)(in T l)
/*const pure nothrow*/ if (isIntegral!T) {
return Rational(l).opBinary!op(Rational(num, den));
}

Rational opUnary(string op)()
/*const pure nothrow*/ if (op == "+" || op == "-") {
return Rational(mixin(op ~ "num"), den);
}

int opCmp(T)(/*in*/ T r) /*const pure nothrow*/ {
Rational rhs = Rational(r);
if (type() == Type.NaRAT || rhs.type() == Type.NaRAT)
throw new Exception("Compare invlove an NaRAT.");
if (type() != Type.NORMAL ||
rhs.type() != Type.NORMAL) // for infinite
return (type() == rhs.type()) ? 0 :
((type() < rhs.type()) ? -1 : 1);
BigInt diff = num * rhs.den - den * rhs.num;
return (diff == 0) ? 0 : ((diff < 0) ? -1 : 1);
}

int opEquals(T)(/*in*/ T r) /*const pure nothrow*/ {
Rational rhs = Rational(r);
if (type() == Type.NaRAT || rhs.type() == Type.NaRAT)
return false;
return num == rhs.num && den == rhs.den;
}

Type type() /*const pure nothrow*/ {
if (den > 0) return Type.NORMAL;
if (den < 0) return Type.NegDEN;
if (num > 0) return Type.PosINF;
if (num < 0) return Type.NegINF;
return Type.NaRAT;
}
}

version (arithmetic_rational_main) { // test part
void main() {
import std.stdio, std.math;

foreach (p; 2 .. 2 ^^ 19) {
auto sum = Rational(1, p);
immutable limit = 1 + cast(uint)sqrt(cast(real)p);
foreach (factor; 2 .. limit)
if (p % factor == 0)
sum = sum + Rational(1, factor) + Rational(factor, p);
if (sum.denominator == 1)
writefln("Sum of recipr. factors of %6s = %s exactly%s",
p, sum, (sum == 1) ? ", perfect." : ".");
}
}
}

--
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
```
Apr 10 2012