138 changes: 91 additions & 47 deletions std/math.d
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,6 @@ $(TR $(TDNW Introspection) $(TD
$(MYREF isNormal) $(MYREF isSubnormal) $(MYREF signbit) $(MYREF sgn)
$(MYREF copysign) $(MYREF isPowerOf2)
))
$(TR $(TDNW Complex Numbers) $(TD
$(MYREF abs) $(MYREF conj) $(MYREF sin) $(MYREF cos) $(MYREF expi)
))
$(TR $(TDNW Hardware Control) $(TD
$(MYREF IeeeFlags) $(MYREF FloatingPointControl)
))
Expand Down Expand Up @@ -507,30 +504,53 @@ enum real SQRT2 = 0x1.6a09e667f3bcc908b2fb1366ea958p+0L; /** $(SQRT)2 = 1.4
enum real SQRT1_2 = SQRT2/2; /** $(SQRT)$(HALF) = 0.707106... */
// Note: Make sure the magic numbers in compiler backend for x87 match these.

// it's quite tricky check for a type who will trigger a deprecation when accessed
template isDeprecatedComplex(T)
{
static if (__traits(isDeprecated, T))
{
enum isDeprecatedComplex = true;
}
else
{
enum m = T.mangleof;
// cfloat, cdouble, creal
// ifloat, idouble, ireal
enum isDeprecatedComplex = m == "q" || m == "r" || m == "c" ||
m == "o" || m == "p" || m == "j";
}
}

deprecated unittest
{
static assert(isDeprecatedComplex!cfloat);
static assert(isDeprecatedComplex!cdouble);
static assert(isDeprecatedComplex!creal);
static assert(isDeprecatedComplex!ifloat);
static assert(isDeprecatedComplex!idouble);
static assert(isDeprecatedComplex!ireal);

static assert(!isDeprecatedComplex!float);
static assert(!isDeprecatedComplex!double);
static assert(!isDeprecatedComplex!real);
}

/***********************************
* Calculates the absolute value of a number
*
* Params:
* Num = (template parameter) type of number
* x = real number value
* z = complex number value
* y = imaginary number value
*
* Returns:
* The absolute value of the number. If floating-point or integral,
* the return type will be the same as the input; if complex or
* imaginary, the returned value will be the corresponding floating
* point type.
*
* For complex numbers, abs(z) = sqrt( $(POWER z.re, 2) + $(POWER z.im, 2) )
* = hypot(z.re, z.im).
* the return type will be the same as the input;
*/
Num abs(Num)(Num x) @safe pure nothrow
if ((is(typeof(Num.init >= 0)) && is(typeof(-Num.init)) ||
(is(Num == short) || is(Num == byte))) &&
!(is(Num* : const(ifloat*)) || is(Num* : const(idouble*))
|| is(Num* : const(ireal*))))
auto abs(Num)(Num x)
// workaround for https://issues.dlang.org/show_bug.cgi?id=18251
//if (!isDeprecatedComplex!Num &&
//(is(typeof(Num.init >= 0)) && is(typeof(-Num.init)) ||
//(is(Num == short) || is(Num == byte))))
{
static if (isFloatingPoint!(Num))
return fabs(x);
Expand All @@ -543,20 +563,22 @@ if ((is(typeof(Num.init >= 0)) && is(typeof(-Num.init)) ||
}
}

/// ditto
auto abs(Num)(Num z) @safe pure nothrow @nogc
if (is(Num* : const(cfloat*)) || is(Num* : const(cdouble*))
|| is(Num* : const(creal*)))
import std.meta : AliasSeq;
deprecated("Please use std.complex")
static foreach (Num; AliasSeq!(cfloat, cdouble, creal, ifloat, idouble, ireal))
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is pretty ugly, but my attempt at working around https://issues.dlang.org/show_bug.cgi?id=18251

{
return hypot(z.re, z.im);
}

/// ditto
auto abs(Num)(Num y) @safe pure nothrow @nogc
if (is(Num* : const(ifloat*)) || is(Num* : const(idouble*))
|| is(Num* : const(ireal*)))
{
return fabs(y.im);
auto abs(Num z) @safe pure nothrow @nogc
{
enum m = Num.mangleof;
// cfloat, cdouble, creal
static if (m == "q" || m == "r" || m == "c")
return hypot(z.re, z.im);
// ifloat, idouble, ireal
else static if (m == "o" || m == "p" || m == "j")
return fabs(z.im);
else
static assert(0, "Unsupported type: " ~ Num.stringof);
}
}

/// ditto
Expand All @@ -565,10 +587,15 @@ if (is(Num* : const(ifloat*)) || is(Num* : const(idouble*))
assert(isIdentical(abs(-0.0L), 0.0L));
assert(isNaN(abs(real.nan)));
assert(abs(-real.infinity) == real.infinity);
assert(abs(-3.2Li) == 3.2L);
assert(abs(71.6Li) == 71.6L);
assert(abs(-56) == 56);
assert(abs(2321312L) == 2321312L);
}

deprecated
@safe pure nothrow @nogc unittest
{
assert(abs(-3.2Li) == 3.2L);
assert(abs(71.6Li) == 71.6L);
assert(abs(-1L+1i) == sqrt(2.0L));
}

Expand All @@ -589,6 +616,12 @@ if (is(Num* : const(ifloat*)) || is(Num* : const(idouble*))
assert(abs(f) == f);
assert(abs(-f) == f);
}}
}

deprecated
@safe pure nothrow @nogc unittest
{
import std.meta : AliasSeq;
static foreach (T; AliasSeq!(cfloat, cdouble, creal))
{{
T f = -12+3i;
Expand All @@ -597,14 +630,15 @@ if (is(Num* : const(ifloat*)) || is(Num* : const(idouble*))
}}
}

/***********************************
/*
* Complex conjugate
*
* conj(x + iy) = x - iy
*
* Note that z * conj(z) = $(POWER z.re, 2) - $(POWER z.im, 2)
* is always a real number
*/
deprecated("Please use std.complex.conj")
auto conj(Num)(Num z) @safe pure nothrow @nogc
if (is(Num* : const(cfloat*)) || is(Num* : const(cdouble*))
|| is(Num* : const(creal*)))
Expand All @@ -617,15 +651,15 @@ if (is(Num* : const(cfloat*)) || is(Num* : const(cdouble*))
return z.re - z.im*1fi;
}

/** ditto */
deprecated("Please use std.complex.conj")
auto conj(Num)(Num y) @safe pure nothrow @nogc
if (is(Num* : const(ifloat*)) || is(Num* : const(idouble*))
|| is(Num* : const(ireal*)))
{
return -y;
}

///
deprecated
@safe pure nothrow @nogc unittest
{
creal c = 7 + 3Li;
Expand All @@ -634,6 +668,7 @@ if (is(Num* : const(ifloat*)) || is(Num* : const(idouble*))
assert(conj(z) == -z);
}
//Issue 14206
deprecated
@safe pure nothrow @nogc unittest
{
cdouble c = 7 + 3i;
Expand All @@ -642,6 +677,7 @@ if (is(Num* : const(ifloat*)) || is(Num* : const(idouble*))
assert(conj(z) == -z);
}
//Issue 14206
deprecated
@safe pure nothrow @nogc unittest
{
cfloat c = 7f + 3fi;
Expand Down Expand Up @@ -724,53 +760,57 @@ float sin(float x) @safe pure nothrow @nogc { return sin(cast(real) x); }
assert(psin != null);
}

/***********************************
/*
* Returns sine for complex and imaginary arguments.
*
* sin(z) = sin(z.re)*cosh(z.im) + cos(z.re)*sinh(z.im)i
*
* If both sin($(THETA)) and cos($(THETA)) are required,
* it is most efficient to use expi($(THETA)).
*/
creal sin(creal z) @safe pure nothrow @nogc
deprecated("Use std.complex.sin")
auto sin(creal z) @safe pure nothrow @nogc
{
const creal cs = expi(z.re);
const creal csh = coshisinh(z.im);
return cs.im * csh.re + cs.re * csh.im * 1i;
}

/** ditto */
ireal sin(ireal y) @safe pure nothrow @nogc
/* ditto */
deprecated("Use std.complex.sin")
auto sin(ireal y) @safe pure nothrow @nogc
{
return cosh(y.im)*1i;
}

///
deprecated
@safe pure nothrow @nogc unittest
{
assert(sin(0.0+0.0i) == 0.0);
assert(sin(2.0+0.0i) == sin(2.0L) );
}

/***********************************
/*
* cosine, complex and imaginary
*
* cos(z) = cos(z.re)*cosh(z.im) - sin(z.re)*sinh(z.im)i
*/
creal cos(creal z) @safe pure nothrow @nogc
deprecated("Use std.complex.cos")
auto cos(creal z) @safe pure nothrow @nogc
{
const creal cs = expi(z.re);
const creal csh = coshisinh(z.im);
return cs.re * csh.re - cs.im * csh.im * 1i;
}

/** ditto */
/* ditto */
deprecated("Use std.complex.cos")
real cos(ireal y) @safe pure nothrow @nogc
{
return cosh(y.im);
}

///
deprecated
@safe pure nothrow @nogc unittest
{
assert(cos(0.0+0.0i)==1.0);
Expand Down Expand Up @@ -1416,7 +1456,8 @@ package:
/* Returns cosh(x) + I * sinh(x)
* Only one call to exp() is performed.
*/
creal coshisinh(real x) @safe pure nothrow @nogc
deprecated("Use std.complex")
auto coshisinh(real x) @safe pure nothrow @nogc
{
// See comments for cosh, sinh.
if (fabs(x) > real.mant_dig * LN2)
Expand All @@ -1431,6 +1472,7 @@ creal coshisinh(real x) @safe pure nothrow @nogc
}
}

deprecated
@safe pure nothrow @nogc unittest
{
creal c = coshisinh(3.0L);
Expand Down Expand Up @@ -1633,7 +1675,8 @@ real sqrt(real x) @nogc @safe pure nothrow { pragma(inline, true); return core.m
assert(psqrtr != null);
}

creal sqrt(creal z) @nogc @safe pure nothrow
deprecated("Use std.complex.sqrt")
auto sqrt(creal z) @nogc @safe pure nothrow
{
creal c;
real x,y,w,r;
Expand Down Expand Up @@ -2538,13 +2581,14 @@ private real exp2Impl(real x) @nogc @trusted pure nothrow
}


/**
/*
* Calculate cos(y) + i sin(y).
*
* On many CPUs (such as x86), this is a very efficient operation;
* almost twice as fast as calculating sin(y) and cos(y) separately,
* and is the preferred method when both are required.
*/
deprecated("Use std.complex.expi")
creal expi(real y) @trusted pure nothrow @nogc
{
version(InlineAsm_X86_Any)
Expand Down Expand Up @@ -2576,7 +2620,7 @@ creal expi(real y) @trusted pure nothrow @nogc
}
}

///
deprecated
@safe pure nothrow @nogc unittest
{
assert(expi(1.3e5L) == cos(1.3e5L) + sin(1.3e5L) * 1i);
Expand Down
9 changes: 8 additions & 1 deletion std/string.d
Original file line number Diff line number Diff line change
Expand Up @@ -6111,7 +6111,6 @@ if (isSomeString!S ||
{
assert(isNumeric(to!string(real.nan)) == true);
assert(isNumeric(to!string(-real.infinity)) == true);
assert(isNumeric(to!string(123e+2+1234.78Li)) == true);
}

string s = "$250.99-";
Expand All @@ -6124,6 +6123,14 @@ if (isSomeString!S ||
assert(!isNumeric("+"));
}

version(TestComplex)
deprecated
unittest
{
import std.conv : to;
assert(isNumeric(to!string(123e+2+1234.78Li)) == true);
}

/*****************************
* Soundex algorithm.
*
Expand Down
22 changes: 14 additions & 8 deletions std/traits.d
Original file line number Diff line number Diff line change
Expand Up @@ -5178,7 +5178,7 @@ template BooleanTypeOf(T)
static assert( is(Q!T == BooleanTypeOf!( SubTypeOf!(Q!T) )));
}

static foreach (T; AliasSeq!(void, NumericTypeList, ImaginaryTypeList, ComplexTypeList, CharTypeList))
static foreach (T; AliasSeq!(void, NumericTypeList, /*ImaginaryTypeList, ComplexTypeList,*/ CharTypeList))
static foreach (Q; TypeQualifierList)
{
static assert(!is(BooleanTypeOf!( Q!T )), Q!T.stringof);
Expand Down Expand Up @@ -5229,7 +5229,7 @@ template IntegralTypeOf(T)
static assert( is(Q!T == IntegralTypeOf!( SubTypeOf!(Q!T) )));
}

static foreach (T; AliasSeq!(void, bool, FloatingPointTypeList, ImaginaryTypeList, ComplexTypeList, CharTypeList))
static foreach (T; AliasSeq!(void, bool, FloatingPointTypeList, /*ImaginaryTypeList, ComplexTypeList,*/ CharTypeList))
static foreach (Q; TypeQualifierList)
{
static assert(!is(IntegralTypeOf!( Q!T )));
Expand Down Expand Up @@ -5264,7 +5264,7 @@ template FloatingPointTypeOf(T)
static assert( is(Q!T == FloatingPointTypeOf!( SubTypeOf!(Q!T) )));
}

static foreach (T; AliasSeq!(void, bool, IntegralTypeList, ImaginaryTypeList, ComplexTypeList, CharTypeList))
static foreach (T; AliasSeq!(void, bool, IntegralTypeList, /*ImaginaryTypeList, ComplexTypeList,*/ CharTypeList))
static foreach (Q; TypeQualifierList)
{
static assert(!is(FloatingPointTypeOf!( Q!T )));
Expand Down Expand Up @@ -5293,7 +5293,7 @@ template NumericTypeOf(T)
static assert( is(Q!T == NumericTypeOf!( SubTypeOf!(Q!T) )));
}

static foreach (T; AliasSeq!(void, bool, CharTypeList, ImaginaryTypeList, ComplexTypeList))
static foreach (T; AliasSeq!(void, bool, CharTypeList, /*ImaginaryTypeList, ComplexTypeList*/))
static foreach (Q; TypeQualifierList)
{
static assert(!is(NumericTypeOf!( Q!T )));
Expand Down Expand Up @@ -5354,7 +5354,7 @@ template CharTypeOf(T)
static assert( is(CharTypeOf!( SubTypeOf!(Q!T) )));
}

static foreach (T; AliasSeq!(void, bool, NumericTypeList, ImaginaryTypeList, ComplexTypeList))
static foreach (T; AliasSeq!(void, bool, NumericTypeList, /*ImaginaryTypeList, ComplexTypeList*/))
static foreach (Q; TypeQualifierList)
{
static assert(!is(CharTypeOf!( Q!T )));
Expand Down Expand Up @@ -5386,7 +5386,7 @@ template StaticArrayTypeOf(T)

@safe unittest
{
static foreach (T; AliasSeq!(bool, NumericTypeList, ImaginaryTypeList, ComplexTypeList))
static foreach (T; AliasSeq!(bool, NumericTypeList, /*ImaginaryTypeList, ComplexTypeList*/))
static foreach (Q; AliasSeq!(TypeQualifierList, InoutOf, SharedInoutOf))
{
static assert(is( Q!( T[1] ) == StaticArrayTypeOf!( Q!( T[1] ) ) ));
Expand Down Expand Up @@ -5423,7 +5423,7 @@ template DynamicArrayTypeOf(T)

@safe unittest
{
static foreach (T; AliasSeq!(/*void, */bool, NumericTypeList, ImaginaryTypeList, ComplexTypeList))
static foreach (T; AliasSeq!(/*void, */bool, NumericTypeList, /*ImaginaryTypeList, ComplexTypeList*/))
static foreach (Q; AliasSeq!(TypeQualifierList, InoutOf, SharedInoutOf))
{
static assert(is( Q!T[] == DynamicArrayTypeOf!( Q!T[] ) ));
Expand Down Expand Up @@ -6090,7 +6090,6 @@ enum bool isEqualityComparable(T) = ifTestable!(T, unaryFun!"a == a");
{
static assert(isEqualityComparable!int);
static assert(isEqualityComparable!string);
static assert(isEqualityComparable!creal);
static assert(!isEqualityComparable!void);

struct Foo {}
Expand All @@ -6110,6 +6109,13 @@ enum bool isEqualityComparable(T) = ifTestable!(T, unaryFun!"a == a");
assert(b1 != b3);
}

version(TestComplex)
deprecated
@safe unittest
{
static assert(isEqualityComparable!creal);
}

/**
* Detect whether $(D T) is a struct, static array, or enum that is implicitly
* convertible to a string.
Expand Down
6 changes: 3 additions & 3 deletions std/typecons.d
Original file line number Diff line number Diff line change
Expand Up @@ -2300,13 +2300,13 @@ string alignForSize(E...)(const char[][] names...)
{
enum x = alignForSize!(int[], char[3], short, double[5])("x", "y","z", "w");
struct Foo { int x; }
enum y = alignForSize!(ubyte, Foo, cdouble)("x", "y", "z");
enum y = alignForSize!(ubyte, Foo, double)("x", "y", "z");

enum passNormalX = x == "double[5] w;\nint[] x;\nshort z;\nchar[3] y;\n";
enum passNormalY = y == "cdouble z;\nFoo y;\nubyte x;\n";
enum passNormalY = y == "double z;\nFoo y;\nubyte x;\n";

enum passAbnormalX = x == "int[] x;\ndouble[5] w;\nshort z;\nchar[3] y;\n";
enum passAbnormalY = y == "Foo y;\ncdouble z;\nubyte x;\n";
enum passAbnormalY = y == "Foo y;\ndouble z;\nubyte x;\n";
// ^ blame http://d.puremagic.com/issues/show_bug.cgi?id=231

static assert(passNormalX || passAbnormalX && double.alignof <= (int[]).alignof);
Expand Down
20 changes: 16 additions & 4 deletions std/variant.d
Original file line number Diff line number Diff line change
Expand Up @@ -1192,6 +1192,7 @@ public:
}
}


@system unittest
{
import std.conv : to;
Expand Down Expand Up @@ -1484,6 +1485,11 @@ be arbitrarily complex.
assert(obj.get!2["customer"] == "John");
}

private struct FakeComplexReal
{
real re, im;
}

/**
Alias for $(LREF VariantN) instantiated with the largest size of `creal`,
`char[]`, and `void delegate()`. This ensures that `Variant` is large enough
Expand All @@ -1492,7 +1498,7 @@ pointers, delegates, and class references. You may want to use
$(D VariantN) directly with a different maximum size either for
storing larger types unboxed, or for saving memory.
*/
alias Variant = VariantN!(maxSize!(creal, char[], void delegate()));
alias Variant = VariantN!(maxSize!(FakeComplexReal, char[], void delegate()));

/**
* Returns an array of variants constructed from $(D args).
Expand Down Expand Up @@ -1770,16 +1776,13 @@ static class VariantException : Exception
{
auto v1 = Variant(42);
auto v2 = Variant("foo");
auto v3 = Variant(1+2.0i);

int[Variant] hash;
hash[v1] = 0;
hash[v2] = 1;
hash[v3] = 2;

assert( hash[v1] == 0 );
assert( hash[v2] == 1 );
assert( hash[v3] == 2 );
}

{
Expand All @@ -1795,6 +1798,15 @@ static class VariantException : Exception
}
}

version(TestComplex)
deprecated
@system unittest
{
auto v3 = Variant(1+2.0i);
hash[v3] = 2;
assert( hash[v3] == 2 );
}

@system unittest
{
// check comparisons incompatible with AllowedTypes
Expand Down
5 changes: 0 additions & 5 deletions unittest.d
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,6 @@ int main(string[] args)
std.zlib.adler32(0,null); // D.zlib
auto t = task!cmp("foo", "bar"); // parallelism

creal c = 3.0 + 4.0i;
c = sqrt(c);
assert(c.re == 2);
assert(c.im == 1);

printf("args.length = %d\n", args.length);
for (int i = 0; i < args.length; i++)
printf("args[%d] = '%.*s'\n", i, args[i].length, args[i].ptr);
Expand Down