RosettaCodeData/Task/Numeric-error-propagation/D/numeric-error-propagation.d

102 lines
2.9 KiB
D

import std.stdio, std.math, std.string, std.typecons, std.traits;
const struct Imprecise {
private const double value, delta;
this(in double v, in double d) pure nothrow {
this.value = v;
this.delta = abs(d);
}
enum IsImprecise(T) = is(Unqual!T == Unqual!(typeof(this)));
I reciprocal() const pure nothrow {
return I(1.0 / value, delta / (value ^^ 2));
}
string toString() const {
return format("I(value=%g, delta=%g)", value, delta);
}
I opUnary(string op:"-")() const pure nothrow {
return I(-this.value, this.delta);
}
I opBinary(string op:"+", T)(in T other) const pure nothrow
if (isNumeric!T || IsImprecise!T) {
static if (IsImprecise!T)
return I(this.value + other.value,
(this.delta ^^ 2 + other.delta ^^ 2) ^^ 0.5);
else
return I(this.value + other, this.delta);
}
I opBinaryRight(string op:"+", T)(in T other) const pure nothrow
if (isNumeric!T) {
return I(this.value + other, this.delta);
}
I opBinary(string op:"-", T)(in T other) const pure nothrow
if (isNumeric!T || IsImprecise!T) {
return this + (-other);
}
I opBinaryRight(string op:"-", T)(in T other) const pure nothrow
if (isNumeric!T) {
return this - other;
}
I opBinary(string op:"*", T)(in T other) const pure nothrow
if (isNumeric!T || IsImprecise!T) {
static if (IsImprecise!T) {
auto f = this.value * other.value;
return I(f, f * ((delta / value) ^^ 2 +
(other.delta / other.value) ^^ 2) ^^ 0.5);
} else
return I(this.value * other, this.delta * other);
}
I opBinaryRight(string op:"*", T)(in T other) const pure nothrow
if (isNumeric!T) {
return this * other;
}
I opBinary(string op:"/", T)(in T other) const pure nothrow
if (isNumeric!T || IsImprecise!T) {
static if (IsImprecise!T)
return this * other.reciprocal();
else
return I(this.value / other, this.delta / other);
}
I opBinaryRight(string op:"/", T)(in T other) const pure nothrow
if (isNumeric!T) {
return this / other;
}
I opBinary(string op:"^^", T)(in T other) const pure nothrow
if (isNumeric!T) {
auto f = this.value ^^ other;
return I(f, f * other * (this.delta / this.value));
}
}
alias I = Imprecise;
auto distance(T1, T2)(in T1 p1, in T2 p2) pure nothrow {
return ((p1[0] - p2[0]) ^^ 2 + (p1[1] - p2[1]) ^^ 2) ^^ 0.5;
}
void main() {
immutable x1 = I(100, 1.1);
immutable x2 = I(200, 2.2);
immutable y1 = I( 50, 1.2);
immutable y2 = I(100, 2.3);
immutable p1 = tuple(x1, y1);
immutable p2 = tuple(x2, y2);
writefln("Point p1: (%s, %s)", p1[0], p1[1]);
writefln("Point p2: (%s, %s)", p2[0], p2[1]);
writeln("Distance(p1, p2): ", distance(p1, p2));
}