Created
February 13, 2013 19:29
-
-
Save Arlen/4947368 to your computer and use it in GitHub Desktop.
Comparison between std.rational and http://rosettacode.org/wiki/Arithmetic/Rational#D
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// source: http://rosettacode.org/wiki/Arithmetic/Rational#D | |
import std.bigint, std.traits, std.conv; | |
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; | |
} | |
struct RationalT(T) { | |
/*const*/ private T num, den; // Numerator & denominator. | |
private enum Type { NegINF = -2, | |
NegDEN = -1, | |
NaRAT = 0, | |
NORMAL = 1, | |
PosINF = 2 }; | |
this(U : RationalT)(U n) pure nothrow { | |
num = n.num; | |
den = n.den; | |
} | |
this(U)(in U n) pure nothrow if (isIntegral!U) { | |
num = toT(n); | |
den = 1UL; | |
} | |
this(U, V)(/*in*/ U n, /*in*/ V d) /*pure nothrow*/ { | |
num = toT(n); | |
den = toT(d); | |
/*const*/ T 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; | |
} | |
} | |
static T toT(U)(/*in*/ ref U n) pure nothrow if (is(U == T)) { | |
return n; | |
} | |
static T toT(U)(in ref U n) pure nothrow if (!is(U == T)) { | |
T result = n; | |
return result; | |
} | |
T nomerator() /*const*/ pure nothrow @property { | |
return num; | |
} | |
T denominator() /*const*/ pure nothrow @property { | |
return den; | |
} | |
string toString() /*const*/ { | |
if (den == 0) { | |
if (num == 0) | |
return "NaRat"; | |
else | |
return ((num < 0) ? "-" : "+") ~ "infRat"; | |
} | |
return text(num) ~ (den == 1 ? "" : ("/" ~ text(den))); | |
} | |
RationalT opBinary(string op)(/*in*/ RationalT r) | |
/*const pure nothrow*/ if (op == "+" || op == "-") { | |
T common = lcm(den, r.den); | |
T n = mixin("common / den * num" ~ op ~ | |
"common / r.den * r.num" ); | |
return RationalT(n, common); | |
} | |
RationalT opBinary(string op)(/*in*/ RationalT r) | |
/*const pure nothrow*/ if (op == "*") { | |
return RationalT(num * r.num, den * r.den); | |
} | |
RationalT opBinary(string op)(/*in*/ RationalT r) | |
/*const pure nothrow*/ if (op == "/") { | |
return RationalT(num * r.den, den * r.num); | |
} | |
RationalT opBinary(string op, U)(in U r) | |
/*const pure nothrow*/ if (isIntegral!U && (op == "+" || | |
op == "-" || op == "*" || op == "/")) { | |
return opBinary!op(RationalT(r)); | |
} | |
RationalT opBinary(string op)(in size_t p) | |
/*const pure nothrow*/ if (op == "^^") { | |
return RationalT(num ^^ p, den ^^ p); | |
} | |
RationalT opBinaryRight(string op, U)(in U l) | |
/*const pure nothrow*/ if (isIntegral!U) { | |
return RationalT(l).opBinary!op(RationalT(num, den)); | |
} | |
RationalT opOpAssign(string op, U)(in U l) | |
/*const pure nothrow*/ { | |
mixin("this = this " ~ op ~ "l;"); | |
return this; | |
} | |
RationalT opUnary(string op)() | |
/*const pure nothrow*/ if (op == "+" || op == "-") { | |
return RationalT(mixin(op ~ "num"), den); | |
} | |
bool opCast(U)() const if (is(U == bool)) { | |
return num != 0; | |
} | |
int opEquals(U)(/*in*/ U r) /*const pure nothrow*/ { | |
RationalT rhs = RationalT(r); | |
if (type() == Type.NaRAT || rhs.type() == Type.NaRAT) | |
return false; | |
return num == rhs.num && den == rhs.den; | |
} | |
int opCmp(U)(/*in*/ U r) /*const pure nothrow*/ { | |
auto rhs = RationalT(r); | |
if (type() == Type.NaRAT || rhs.type() == Type.NaRAT) | |
throw new Exception("Compare involve a NaRAT."); | |
if (type() != Type.NORMAL || | |
rhs.type() != Type.NORMAL) // for infinite | |
return (type() == rhs.type()) ? 0 : | |
((type() < rhs.type()) ? -1 : 1); | |
U diff = num * rhs.den - den * rhs.num; | |
return (diff == 0) ? 0 : ((diff < 0) ? -1 : 1); | |
} | |
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; | |
} | |
} | |
import std.datetime, std.stdio, std.rational; | |
alias RQ = RationalT!long; // Rosetta RationalT | |
alias RQ2 = RationalT!(immutable long); | |
alias SQ1 = Rational!long; // std.rational | |
alias SQ2 = Rational!(immutable long); // std.rational immutable | |
void ben(alias fun, string time = "msecs")(string msg, uint n = 10_000_000) { | |
auto b = benchmark!fun(n); | |
writefln(" %s: %s ms", msg, b[0].to!(time, int)); | |
} | |
void main() | |
{ | |
RQ r1 = RQ(16, 78); | |
RQ r2 = RQ(2, 3); | |
RQ2 r3 = RQ2(16, 78); | |
RQ2 r4 = RQ2(2, 3); | |
SQ1 s1 = SQ1(16, 78); | |
SQ1 s2 = SQ1(2, 3); | |
SQ2 s3 = SQ2(16, 78); | |
SQ2 s4 = SQ2(2, 3); | |
ben!( {auto x = r1 + r2;} )("Rosetta rational + rational"); | |
ben!( {auto x = r3 + r4;} )("Rosetta immutable rational + rational"); | |
ben!( {auto x = s1 + s2;} )("std rational + rational"); | |
ben!( {auto x = s3 + s4;} )("std immutable rational + rational"); | |
writeln(); | |
ben!( {auto x = r1 - r2;} )("Rosetta rational - rational"); | |
ben!( {auto x = r3 - r4;} )("Rosetta immutable rational - rational"); | |
ben!( {auto x = s1 - s2;} )("std rational - rational"); | |
ben!( {auto x = s3 - s4;} )("std immutable rational - rational"); | |
writeln(); | |
ben!( {auto x = r1 * r2;} )("Rosetta rational * rational"); | |
ben!( {auto x = r3 * r4;} )("Rosetta immutable rational * rational"); | |
ben!( {auto x = s1 * s2;} )("std rational * rational"); | |
ben!( {auto x = s3 * s4;} )("std immutable rational * rational"); | |
writeln(); | |
ben!( {auto x = r1 / r2;} )("Rosetta rational / rational"); | |
ben!( {auto x = r3 / r4;} )("Rosetta immutable rational / rational"); | |
ben!( {auto x = s1 / s2;} )("std rational / rational"); | |
ben!( {auto x = s3 / s4;} )("std immutable rational / rational"); | |
writeln(); | |
ben!( {auto x = r1 == r2;} )("Rosetta rational == rational"); | |
ben!( {auto x = r3 == r4;} )("Rosetta immutable rational == rational"); | |
ben!( {auto x = s1 == s2;} )("std rational == rational"); | |
ben!( {auto x = s3 == s4;} )("std immutable rational == rational"); | |
writeln(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment