Skip to content

Instantly share code, notes, and snippets.

@Arlen
Created February 13, 2013 19:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Arlen/4947368 to your computer and use it in GitHub Desktop.
Save Arlen/4947368 to your computer and use it in GitHub Desktop.
Comparison between std.rational and http://rosettacode.org/wiki/Arithmetic/Rational#D
// 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