From e4cd57a61543833c00b3e6a7254962b385db5ef2 Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Mon, 2 Oct 2017 14:55:30 +0200 Subject: [PATCH] math.nbtheory: Implement natural logarithm --- arch/build.ninja | 3 +- arch/x64/linux/math/log.S | 48 +++++++++++++++++++++ source/tanya/container/string.d | 49 ++++++++++----------- source/tanya/math/nbtheory.d | 76 +++++++++++++++++++++++++++++---- 4 files changed, 143 insertions(+), 33 deletions(-) create mode 100644 arch/x64/linux/math/log.S diff --git a/arch/build.ninja b/arch/build.ninja index fce2838..824efa4 100644 --- a/arch/build.ninja +++ b/arch/build.ninja @@ -5,9 +5,10 @@ rule archive command = ar rcs $out $in build abs.o: gas x64/linux/math/abs.S +build log.o: gas x64/linux/math/log.S build cmp.o: gas x64/linux/memory/cmp.S build fill.o: gas x64/linux/memory/fill.S build copy.o: gas x64/linux/memory/copy.S build syscall.o: gas x64/linux/syscall.S -build tanya.a: archive syscall.o copy.o fill.o cmp.o abs.o +build tanya.a: archive syscall.o copy.o fill.o cmp.o log.o abs.o diff --git a/arch/x64/linux/math/log.S b/arch/x64/linux/math/log.S new file mode 100644 index 0000000..7f23703 --- /dev/null +++ b/arch/x64/linux/math/log.S @@ -0,0 +1,48 @@ + .text + + +// logl. + .globl _D5tanya4math8nbtheory2lnFNaNbNiNfeZe + .type _D5tanya4math8nbtheory2lnFNaNbNiNfeZe, @function + +_D5tanya4math8nbtheory2lnFNaNbNiNfeZe: + fldln2 // Put lb(e) onto the FPU stack + fldt 8(%rsp) // Put the argument onto the FPU stack + fyl2x // %st1 * lb(%st0) + ret + + +// log. + .globl _D5tanya4math8nbtheory2lnFNaNbNiNfdZd + .type _D5tanya4math8nbtheory2lnFNaNbNiNfdZd, @function + +_D5tanya4math8nbtheory2lnFNaNbNiNfdZd: + movsd %xmm0, -8(%rsp) // Put the argument onto the stack + + fldln2 // Put lb(e) onto the FPU stack + fldl -8(%rsp) // Put a double onto the FPU stack + fyl2x // %st1 * lb(%st0) + + // The result is on the FPU stack, but returned in %xmm0 + fstpl -8(%rsp) + movsd -8(%rsp), %xmm0 + + ret + + +// logf. + .globl _D5tanya4math8nbtheory2lnFNaNbNiNffZf + .type _D5tanya4math8nbtheory2lnFNaNbNiNffZf, @function + +_D5tanya4math8nbtheory2lnFNaNbNiNffZf: + movss %xmm0, -4(%rsp) // Put the argument onto the stack + + fldln2 // Put lb(e) onto the FPU stack + flds -4(%rsp) // Put a float onto the FPU stack + fyl2x // %st1 * lb(%st0) + + // The result is on the FPU stack, but returned in %xmm0 + fstps -4(%rsp) + movss -4(%rsp), %xmm0 + + ret diff --git a/source/tanya/container/string.d b/source/tanya/container/string.d index a89fe0c..b0bbeec 100644 --- a/source/tanya/container/string.d +++ b/source/tanya/container/string.d @@ -35,6 +35,7 @@ import tanya.memory; import tanya.meta.trait; import tanya.meta.transform; import tanya.range.array; +import tanya.range.primitive; /** * Thrown on encoding errors. @@ -352,9 +353,9 @@ struct String * Precondition: $(D_INLINECODE allocator is null). */ this(S)(const S str, shared Allocator allocator = defaultAllocator) - if (!std.range.isInfinite!S - && std.range.isInputRange!S - && isSomeChar!(std.range.ElementEncodingType!S)) + if (!isInfinite!S + && isInputRange!S + && isSomeChar!(ElementType!S)) { this(allocator); insertBack(str); @@ -667,12 +668,12 @@ struct String * Throws: $(D_PSYMBOL UTFException). */ size_t insertBack(R)(R str) @trusted - if (!std.range.isInfinite!R - && std.range.isInputRange!R - && is(Unqual!(std.range.ElementEncodingType!R) == char)) + if (!isInfinite!R + && isInputRange!R + && is(Unqual!(ElementType!R) == char)) { size_t size; - static if (std.range.hasLength!R || isNarrowString!R) + static if (hasLength!R || isNarrowString!R) { size = str.length + length; reserve(size); @@ -731,11 +732,11 @@ struct String /// ditto size_t insertBack(R)(R str) @trusted - if (!std.range.isInfinite!R - && std.range.isInputRange!R - && is(Unqual!(std.range.ElementEncodingType!R) == wchar)) + if (!isInfinite!R + && isInputRange!R + && is(Unqual!(ElementType!R) == wchar)) { - static if (std.range.hasLength!R || isNarrowString!R) + static if (hasLength!R || isNarrowString!R) { reserve(length + str.length * wchar.sizeof); } @@ -797,11 +798,11 @@ struct String /// ditto size_t insertBack(R)(R str) @trusted - if (!std.range.isInfinite!R - && std.range.isInputRange!R - && is(Unqual!(std.range.ElementEncodingType!R) == dchar)) + if (!isInfinite!R + && isInputRange!R + && is(Unqual!(ElementType!R) == dchar)) { - static if (std.range.hasLength!R || isSomeString!R) + static if (hasLength!R || isSomeString!R) { reserve(length + str.length * 4); } @@ -1268,9 +1269,9 @@ struct String * Throws: $(D_PSYMBOL UTFException). */ ref String opAssign(S)(S that) nothrow - if (!std.range.isInfinite!S - && std.range.isInputRange!S - && isSomeChar!(std.range.ElementEncodingType!S)) + if (!isInfinite!S + && isInputRange!S + && isSomeChar!(ElementType!S)) { this.length_ = 0; insertBack(that); @@ -1531,9 +1532,9 @@ struct String * Precondition: $(D_PARAM r) refers to a region of $(D_KEYWORD this). */ size_t insertAfter(T, R)(R r, T el) @trusted - if ((isSomeChar!T || (!std.range.isInfinite!T - && std.range.isInputRange!T - && isSomeChar!(std.range.ElementEncodingType!T))) + if ((isSomeChar!T || (!isInfinite!T + && isInputRange!T + && isSomeChar!(ElementType!T))) && (is(R == ByCodeUnit!char) || is(R == ByCodePoint!char))) in { @@ -1564,9 +1565,9 @@ struct String /// size_t insertBefore(T, R)(R r, T el) @trusted - if ((isSomeChar!T || (!std.range.isInfinite!T - && std.range.isInputRange!T - && isSomeChar!(std.range.ElementEncodingType!T))) + if ((isSomeChar!T || (!isInfinite!T + && isInputRange!T + && isSomeChar!(ElementType!T))) && (is(R == ByCodeUnit!char) || is(R == ByCodePoint!char))) in { diff --git a/source/tanya/math/nbtheory.d b/source/tanya/math/nbtheory.d index 6be04b9..4c94550 100644 --- a/source/tanya/math/nbtheory.d +++ b/source/tanya/math/nbtheory.d @@ -17,6 +17,15 @@ module tanya.math.nbtheory; import tanya.math.mp; import tanya.meta.trait; +version (TanyaNative) +{ +} +else +{ + import core.math : fabs; + import std.math : log; +} + /** * Calculates the absolute value of a number. * @@ -57,21 +66,19 @@ version (D_Ddoc) I abs(I)(I x) if (isFloatingPoint!I); } -else version (TanyaPhobos) +else version (TanyaNative) +{ + extern I abs(I)(I number) pure nothrow @safe @nogc + if (isFloatingPoint!I); +} +else { - import core.math; - I abs(I)(I x) if (isFloatingPoint!I) { return fabs(cast(real) x); } } -else -{ - extern I abs(I)(I number) pure nothrow @safe @nogc - if (isFloatingPoint!I); -} /// pure nothrow @safe @nogc unittest @@ -103,3 +110,56 @@ I abs(I : Integer)(I x) x.sign = Sign.positive; return x; } + +version (D_Ddoc) +{ + /** + * Calculates natural logarithm of $(D_PARAM x). + * + * Params: + * x = Argument. + * + * Returns: Natural logarithm of $(D_PARAM x). + */ + float ln(float x) pure nothrow @safe @nogc; + /// ditto + double ln(double x) pure nothrow @safe @nogc; + /// ditto + real ln(real x) pure nothrow @safe @nogc; +} +else version (TanyaNative) +{ + extern float ln(float x) pure nothrow @safe @nogc; + extern double ln(double x) pure nothrow @safe @nogc; + extern real ln(real x) pure nothrow @safe @nogc; +} +else +{ + float ln(float x) pure nothrow @safe @nogc + { + return log(x); + } + double ln(double x) pure nothrow @safe @nogc + { + return log(x); + } + alias ln = log; +} + +/// +pure nothrow @safe @nogc unittest +{ + import tanya.math; + + assert(isNaN(ln(-7.389f))); + assert(isNaN(ln(-7.389))); + assert(isNaN(ln(-7.389L))); + + assert(isInfinity(ln(0.0f))); + assert(isInfinity(ln(0.0))); + assert(isInfinity(ln(0.0L))); + + assert(ln(1.0f) == 0.0f); + assert(ln(1.0) == 0.0); + assert(ln(1.0L) == 0.0L); +}