October 07, 2008 Re: Units of Measure in F# | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | Reply to bearophile, > BCS: > >> take a look at si.d first as it's the most useful intro (look way >> down at the bottom) >> > I think there's a need of some syntactic sugar :-) > > Bye, > bearophile I put up some better examples. http://www.dsource.org/projects/scrapple/browser/trunk/units/si.d |
October 09, 2008 Re: Units of Measure in F# | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | This has been done in D already: ---------------------------------- // by Oskar Linde Aug 2006 // This is just a quick hack to test // IFTI operators opMul and opDel import std.stdio; import std.math; import std.string; version = unicode; struct SiQuantity(T,int e1, int e2, int e3, int e4, int e5, int e6, int e7) { T value = 0; alias T ValueType; const exp1 = e1; const exp2 = e2; const exp3 = e3; const exp4 = e4; const exp5 = e5; const exp6 = e6; const exp7 = e7; static assert(SiQuantity.sizeof == ValueType.sizeof); template AddDimensions(int mul, U) { static assert(is(U.ValueType == ValueType) || is(U == ValueType), "incompatible value types"); static if (is(U == ValueType)) alias SiQuantity AddDimensions; else alias SiQuantity!(T,exp1+mul*U.exp1,exp2+mul*U.exp2, exp3+mul*U.exp3,exp4+mul*U.exp4, exp5+mul*U.exp5,exp6+mul*U.exp6, exp7+U.exp7) AddDimensions; } SiQuantity opAddAssign(SiQuantity rhs) { value += rhs.value; return *this; } SiQuantity opSubAssign(SiQuantity rhs) { value -= rhs.value; return *this; } const { SiQuantity opAdd(SiQuantity rhs) { SiQuantity ret; ret.value = value + rhs.value; return ret; } SiQuantity opSub(SiQuantity rhs) { SiQuantity ret; ret.value = value - rhs.value; return ret; } SiQuantity opNeg() { SiQuantity ret; ret.value = -value; return ret; } SiQuantity opPos() { typeof(return) ret; ret.value = value; return ret; } int opCmp(SiQuantity rhs) { if (value > rhs.value) return 1; if (value < rhs.value) return -1; return 0; // BUG: NaN } AddDimensions!(+1,Rhs) opMul(Rhs)(Rhs rhs) { AddDimensions!(+1,Rhs) ret; static if (is(Rhs : T)) ret.value = value * rhs; else ret.value = value * rhs.value; return ret; } AddDimensions!(-1,Rhs) opDiv(Rhs)(Rhs rhs) { AddDimensions!(-1,Rhs) ret; static if (is(Rhs : T)) ret.value = value / rhs; else ret.value = value / rhs.value; return ret; } SiQuantity opMul_r(T lhs) { SiQuantity ret; ret.value = lhs * value; return ret; } SiQuantity!(T,-e1,-e2,-e3,-e4,-e5,-e6,-e7) opDiv_r(T lhs) { SiQuantity!(T,-e1,-e2,-e3,-e4,-e5,-e6,-e7) ret; ret.value = lhs / value; return ret; } string toString() { string prefix = ""; T multiplier = 1; T value = this.value; string unit; static if (is(typeof(UnitName!(SiQuantity)))) unit = UnitName!(SiQuantity); else { value *= pow(cast(real)1e3,cast(uint)e2); // convert kg -> g // Take mass (e2) first to handle kg->g prefix issue if (e2 != 0) unit ~= format("·g^%s",e2); if (e1 != 0) unit ~= format("·m^%s",e1); if (e3 != 0) unit ~= format("·s^%s",e3); if (e4 != 0) unit ~= format("·A^%s",e4); if (e5 != 0) unit ~= format("·K^%s",e5); if (e6 != 0) unit ~= format("·mol^%s",e6); if (e7 != 0) unit ~= format("·cd^%s",e7); if (unit) unit = unit[2..$].split("^1").join(""); } if (value >= 1e24) { prefix = "Y"; multiplier = 1e24; } else if (value >= 1e21) { prefix = "Z"; multiplier = 1e21; } else if (value >= 1e18) { prefix = "E"; multiplier = 1e18; } else if (value >= 1e15) { prefix = "P"; multiplier = 1e15; } else if (value >= 1e12) { prefix = "T"; multiplier = 1e12; } else if (value >= 1e9) { prefix = "G"; multiplier = 1e9; } else if (value >= 1e6) { prefix = "M"; multiplier = 1e6; } else if (value >= 1e3) { prefix = "k"; multiplier = 1e3; } else if (value >= 1) { } else if (value >= 1e-3) { prefix = "m"; multiplier = 1e-3; } else if (value >= 1e-6) { version(unicode) prefix = "µ"; else prefix = "u"; multiplier = 1e-6; } else if (value >= 1e-9) { prefix = "n"; multiplier = 1e-9; } else if (value >= 1e-12) { prefix = "p"; multiplier = 1e-12; } else if (value >= 1e-15) { prefix = "f"; multiplier = 1e-15; } else if (value >= 1e-18) { prefix = "a"; multiplier = 1e-18; } else if (value >= 1e-21) { prefix = "z"; multiplier = 1e-21; } else if (value >= 1e-24) { prefix = "y"; multiplier = 1e-24; } return format("%.3s %s%s",value/multiplier, prefix, unit); } } } //length meter m //mass kilogram kg //time second s //electric current ampere A //thermodynamic temperature kelvin K //amount of substance mole mol //luminous intensity candela cd // Si base quantities alias SiQuantity!(real,1,0,0,0,0,0,0) Length; alias SiQuantity!(real,0,1,0,0,0,0,0) Mass; alias SiQuantity!(real,0,0,1,0,0,0,0) Time; alias SiQuantity!(real,0,0,0,1,0,0,0) Current; alias SiQuantity!(real,0,0,0,0,1,0,0) Temperature; alias SiQuantity!(real,0,0,0,0,0,1,0) AmountOfSubstance; alias SiQuantity!(real,0,0,0,0,0,0,1) Intensity; alias SiQuantity!(real,0,0,0,0,0,0,0) UnitLess; // Derived quantities alias typeof(Length*Length) Area; alias typeof(Length*Area) Volume; alias typeof(Mass/Volume) Density; alias typeof(Length*Mass/Time/Time) Force; alias typeof(1/Time) Frequency; alias typeof(Force/Area) Pressure; alias typeof(Force*Length) Energy; alias typeof(Energy/Time) Power; alias typeof(Time*Current) Charge; alias typeof(Power/Current) Voltage; alias typeof(Charge/Voltage) Capacitance; alias typeof(Voltage/Current) Resistance; alias typeof(1/Resistance) Conductance; alias typeof(Voltage*Time) MagneticFlux; alias typeof(MagneticFlux/Area) MagneticFluxDensity; alias typeof(MagneticFlux/Current) Inductance; alias typeof(Intensity*UnitLess) LuminousFlux; alias typeof(LuminousFlux/Area) Illuminance; // SI fundamental units const Length meter = {1}; const Mass kilogram = {1}; const Time second = {1}; const Current ampere = {1}; const Temperature kelvin = {1}; const AmountOfSubstance mole = {1}; const Intensity candela = {1}; // Derived units const Frequency hertz = {1}; const Force newton = {1}; const Pressure pascal = {1}; const Energy joule = {1}; const Power watt = {1}; const Charge coulomb = {1}; const Voltage volt = {1}; const Capacitance farad = {1}; const Resistance ohm = {1}; const Conductance siemens = {1}; const MagneticFlux weber = {1}; const MagneticFluxDensity tesla = {1}; const Inductance henry = {1}; const LuminousFlux lumen = {1}; const Illuminance lux = {1}; template UnitName(U:Frequency) { const UnitName = "Hz"; } template UnitName(U:Force) { const UnitName = "N"; } template UnitName(U:Pressure) { const UnitName = "Pa"; } template UnitName(U:Energy) { const UnitName = "J"; } template UnitName(U:Power) { const UnitName = "W"; } template UnitName(U:Charge) { const UnitName = "C"; } template UnitName(U:Voltage) { const UnitName = "V"; } template UnitName(U:Capacitance){ const UnitName = "F"; } version(unicode) { template UnitName(U:Resistance) { const UnitName = "Ω"; } } else { template UnitName(U:Resistance) { const UnitNAme = "ohm"; } } template UnitName(U:Conductance){ const UnitName = "S"; } template UnitName(U:MagneticFlux){ const UnitName = "Wb"; } template UnitName(U:MagneticFluxDensity) { const UnitName = "T"; } template UnitName(U:Inductance) { const UnitName = "H"; } void main() { Area a = 25 * meter * meter; Length l = 10 * 1e3 * meter; Volume vol = a * l; Mass m = 100 * kilogram; assert(!is(typeof(vol / m) == Density)); //Density density = vol / m; // dimension error -> syntax error Density density = m / vol; writefln("The volume is %s",vol.toString); writefln("The mass is %s",m.toString); writefln("The density is %s",density.toString); writef("\nElectrical example:\n\n"); Voltage v = 5 * volt; Resistance r = 1 * 1e3 * ohm; Current i = v/r; Time ti = 1 * second; Power w = v*v/r; Energy e = w * ti; // One wishes the .toString was unnecessary... writefln("A current of ",i.toString); writefln("through a voltage of ",v.toString); writefln("requires a resistance of ",r.toString); writefln("and produces ",w.toString," of heat."); writefln("Total energy used in ",ti.toString," is ",e.toString); writef("\nCapacitor time curve:\n\n"); Capacitance C = 0.47 * 1e-6 * farad; // Capacitance Voltage V0 = 5 * volt; // Starting voltage Resistance R = 4.7 * 1e3 * ohm; // Resistance for (Time t; t < 51 * 1e-3 * second; t += 1e-3 * second) { Voltage Vt = V0 * exp((-t / (R*C)).value); writefln("at %5s the voltage is %s",t.toString,Vt.toString); } } |
October 09, 2008 Re: Units of Measure in F# | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright | Reply to Walter,
> This has been done in D already:
It has some interesting features :) (I might have to steal a few for my version)
|
October 09, 2008 Re: Units of Measure in F# | ||||
---|---|---|---|---|
| ||||
Posted in reply to BCS | On Thu, 09 Oct 2008 23:35:58 +0400, BCS <ao@pathlink.com> wrote:
> Reply to Walter,
>
>> This has been done in D already:
>
> It has some interesting features :) (I might have to steal a few for my version)
>
>
I still think my version is superior (it handled floating point powers, supports an arbitrary number of basic units (given that they are orthogonal) and allows adding them with no original code modification) :p
|
October 09, 2008 Re: Units of Measure in F# | ||||
---|---|---|---|---|
| ||||
Posted in reply to Denis Koroskin | Reply to Denis, > On Thu, 09 Oct 2008 23:35:58 +0400, BCS <ao@pathlink.com> wrote: > >> Reply to Walter, >> >>> This has been done in D already: >>> >> It has some interesting features :) (I might have to steal a few for >> my version) >> > I still think my version is superior (it handled floating point > powers, Re: FP, I would count that as worse than basic integers because it runs the risk of FP rounding errors. Mine will handle rational powers (1/2, 23/43, etc) and won't suffer from the loss of precision. The only places I have ever seen non rational exponents in use are in data fitting applications and just switching to a close enough rational is as good as anything there. Also, the non rational cases where mine might suffer little are the cases where FP problem are /most/ likely to crop up. > supports an arbitrary number of basic units (given that they > are orthogonal) and allows adding them with no original code > modification) :p > You may have me on for that point, but extensibility also has it's down side; different people add the same dimension independently and then someone wants to mix them. The 5 dimensions I picked will cover almost all that cases for just about anyone. I think we each picked a different set of design choices and created a solution for them. I do think that mine is better than yours by the criteria I'm using. I can see legitimate criteria where yours is better. |
Copyright © 1999-2021 by the D Language Foundation