Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import std.stdio;
- import std.traits;
- import std.range;
- import std.conv;
- import std.math;
- import std.algorithm;
- template mostPrecise(T, U) {
- static if(!isNumeric!T || !isNumeric!U) {
- static assert(0, "Arguments must be numeric.");
- }
- static if(isFloatingPoint!T && isFloatingPoint!U) {
- static if(T.sizeof > U.sizeof) {
- alias mostPrecise = T;
- } else {
- alias mostPrecise = U;
- }
- } else static if(!isFloatingPoint!T && isFloatingPoint!U) {
- static if(T.sizeof <= 32) {
- alias mostPrecise = mostPrecise!(float, U);
- } else static if(T.sizeof <= 64) {
- alias mostPrecise = mostPrecise!(double, U);
- } else {
- alias mostPrecise = real;
- }
- } else static if(!isFloatingPoint!U && isFloatingPoint!T) {
- alias mostPrecise = mostPrecise!(U, T);
- } else { // !isFloatingPoint!T && !isFloatingPoint!U
- static if(T.sizeof > U.sizeof) {
- alias mostPrecise = T;
- } else {
- alias mostPrecise = U;
- }
- }
- }
- template Dimension(T, long[7] _powers) {
- static long[] addPowers(string op)(long[] a, long[] b) {
- long[] c;
- for(uint i = 0; i < 7; i++) {
- mixin("c[i] = a[i] " ~ op ~ " b[i];");
- }
- }
- static long minPower(long[] powers) {
- long m = long.max;
- for(uint i = 0; i < 7; i++) {
- m = min(m, powers[i]);
- }
- return m;
- }
- static ubyte numPowers(string op)(long[] powers) {
- ubyte n;
- for(uint i = 0; i < 7; i++) {
- if(mixin("powers[i] " ~ op ~ " 0")) {
- n++;
- }
- }
- return n;
- }
- pragma(msg, numPowers!("==")(_powers).to!string);
- static if(!isNumeric!T) {
- static assert(0, "Dimension cannot be instantiated with non-numeric type.");
- } else static if(numPowers!("==")(_powers)) {
- alias Dimension = T;
- } else {
- struct Dimension {
- public static const long[7] powers = _powers.dup;
- private static const string unitNames = [ "m", "kg", "s", "A", "K", "mol", "cd" ];
- public T value;
- this(T value) {
- this.value = value;
- }
- void opAssign(T value) {
- this.value = value;
- }
- auto opBinary(string op, V)(V rhs) {
- static if(op == "+") {
- static if(!is(typeof(this) == V)) {
- static assert(0, "Cannot add unlike dimensions " ~ stringof ~ " and " ~ V.stringof ~ ".");
- }
- alias D = Dimension!(mostPrecise!(T, typeof(V.value)), V.powers);
- return D(this.value + rhs.value);
- } else static if(op == "-") {
- static if(!is(typeof(this) == V)) {
- static assert(0, "Cannot subtract unlike dimensions " ~ stringof ~ " and " ~ V.stringof ~ ".");
- }
- alias D = Dimension!(mostPrecise!(T, typeof(V.value)), V.powers);
- return D(this.value - rhs.value);
- } else static if(op == "*") {
- alias D = Dimension!(mostPrecise!(T, typeof(V.value)), addPowers!("+")(powers, V.powers));
- return D(this.value * rhs.value);
- } else static if(op == "/") {
- alias D = Dimension!(mostPrecise!(T, typeof(V.value)), addPowers!("-")(powers, V.powers));
- return D(this.value / rhs.value);
- } else {
- static assert(0, "Unsupported operator " ~ op ~ " for dimension type.");
- }
- }
- template getUnit() {
- static const string getUnit = (() {
- char[] ret;
- bool hasNeg = minPower(powers) < 0;
- ubyte numTop = numPowers!(">")(powers);
- ubyte numBottom = numPowers!("<")(powers);
- numTop = (lpower > 0) + (mpower > 0) + (tpower > 0);
- numBottom = (lpower < 0) + (mpower < 0) + (tpower < 0);
- bool mul = false;
- if(numTop > 1 && numTop > 1) {
- ret ~= "(";
- }
- if(powers[i] > 0) {
- ret ~= unitNames[0];
- if(powers[i] > 1) {
- ret ~= "^" ~ powers[i].to!string;
- }
- mul = true;
- }
- for(uint i = 1; i < powers.length; i++) {
- if(powers[i] > 0) {
- ret ~= (mul ? "*" : "") ~ unitNames[i];
- if(powers[i] > 1) {
- ret ~= "^" ~ powers[i].to!string;
- }
- mul = true;
- }
- }
- if(numTop > 1 && numTop > 1) {
- ret ~= ")";
- }
- if(numBottom > 0) {
- ret ~= "/";
- mul = false;
- if(numTop > 1 && numTop > 1) {
- ret ~= "(";
- }
- if(powers[0] < 0) {
- ret ~= lstr;
- if(powers[0] < -1) {
- ret ~= "^" ~ (-powers[0]).to!string;
- }
- mul = true;
- }
- for(uint i = 0; i < powers.length; i++) {
- if(powers[i] < 0) {
- ret ~= (mul ? "*" : "") ~ unitNames[i];
- if(powers[i] < -1) {
- ret ~= "^" ~ (-powers[i]).to!string;
- }
- mul = true;
- }
- }
- if(numTop > 1 && numTop > 1) {
- ret ~= ")";
- }
- }
- return ret;
- })();
- }
- public static const string stringof = getUnit!();
- string toString() {
- return value.to!string ~ stringof;
- }
- }
- }
- }
- template Compose(alias e) {
- auto Compose(T)(T value = 0) {
- alias D = Dimension!(T, e.powers.dup);
- return D(value);
- }
- }
- auto Length(T)(T value = 0) {
- return Dimension!(T, [ 1, 0, 0, 0, 0, 0, 0 ])(value);
- }
- auto Mass(T)(T value = 0) {
- return Dimension!(T, [ 0, 1, 0, 0, 0, 0, 0 ])(value);
- }
- auto Time(T)(T value = 0) {
- return Dimension!(T, [ 0, 0, 1, 0, 0, 0, 0 ])(value);
- }
- void main() {
- pragma(msg, typeof(Length(20)));
- alias V = typeof(Length(1) * Length(1));
- pragma(msg, V.stringof);
- alias Area = Compose!(Length * Length);
- alias Volume = Compose!(Area * Length);
- alias Velocity = Compose!(Length / Time(1));
- alias Acceleration = Compose!(Velocity / Time(1));
- alias Force = Compose!(Mass * Acceleration);
- alias Work = Compose!(Force * Length);
- alias Power = Compose!(Work / Time(1));
- auto mass = Mass(63.5);
- auto g = Acceleration(9.8);
- auto f = mass * g;
- writeln("My mass is " ~ mass.to!string ~ ".");
- writeln("The acceleration due to gravity on Earth is " ~ g.to!string ~ ".");
- writeln("I exert a force of " ~ f.to!string ~ "on the ground.");
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement