diff --git a/arch/build.ninja b/arch/build.ninja index 42ee8f6..eff2eb9 100644 --- a/arch/build.ninja +++ b/arch/build.ninja @@ -4,6 +4,7 @@ rule gas rule archive command = ar rcs $out $in +build abs.o: gas x64/linux/math/abs.S build syscall.o: gas x64/linux/syscall.S -build tanya.a: archive syscall.o +build tanya.a: archive syscall.o abs.o diff --git a/arch/x64/linux/math/abs.S b/arch/x64/linux/math/abs.S new file mode 100644 index 0000000..edf8ac9 --- /dev/null +++ b/arch/x64/linux/math/abs.S @@ -0,0 +1,35 @@ + .text + + +// fabsf. + .globl _D5tanya4math8nbtheory10__T3absTfZ3absFNaNbNiNffZf + .type _D5tanya4math8nbtheory10__T3absTfZ3absFNaNbNiNffZf, @function + +_D5tanya4math8nbtheory10__T3absTfZ3absFNaNbNiNffZf: + mov $0x7fffffff, %eax + movq %rax, %xmm1 + andpd %xmm1, %xmm0 + ret + + +// fabs. + .globl _D5tanya4math8nbtheory10__T3absTdZ3absFNaNbNiNfdZd + .type _D5tanya4math8nbtheory10__T3absTdZ3absFNaNbNiNfdZd, @function + +_D5tanya4math8nbtheory10__T3absTdZ3absFNaNbNiNfdZd: + mov $0x7fffffffffffffff, %rax + movq %rax, %xmm1 + andpd %xmm1, %xmm0 + ret + + +// fabsl. + .globl _D5tanya4math8nbtheory10__T3absTeZ3absFNaNbNiNfeZe + .type _D5tanya4math8nbtheory10__T3absTeZ3absFNaNbNiNfeZe, @function + +// Load the parameter from the stack onto FP stack, execute 'fabs' instruction +// The result is returned in ST0. +_D5tanya4math8nbtheory10__T3absTeZ3absFNaNbNiNfeZe: + fldt 0x8(%rsp) + fabs + ret diff --git a/dub.json b/dub.json index 446d4ce..e6dfaaf 100644 --- a/dub.json +++ b/dub.json @@ -18,7 +18,9 @@ { "name": "native", "targetType": "library", - "platforms": ["linux-x86_64"] + "platforms": ["linux-x86_64"], + "preBuildCommands": ["ninja -C arch"], + "lflags": ["arch/tanya.a"] } ] } diff --git a/source/tanya/math/nbtheory.d b/source/tanya/math/nbtheory.d new file mode 100644 index 0000000..09af9cf --- /dev/null +++ b/source/tanya/math/nbtheory.d @@ -0,0 +1,165 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/** + * Number theory. + * + * Copyright: Eugene Wissner 2017. + * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, + * Mozilla Public License, v. 2.0). + * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) + * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/math/nbtheory.d, + * tanya/math/nbtheory.d) + */ +module tanya.math.nbtheory; + +import tanya.math.mp; +import tanya.meta.trait; + +/** + * Floating-point number precisions according to IEEE-754. + */ +enum IEEEPrecision : ubyte +{ + /// Single precision: 64-bit. + single = 4, + + /// Single precision: 64-bit. + double_ = 8, + + /// Extended precision: 80-bit. + extended = 10, +} + +/** + * Tests the precision of floating-point type $(D_PARAM F). + * + * For $(D_KEYWORD float), $(D_PSYMBOL ieeePrecision) always evaluates to + * $(D_INLINECODE IEEEPrecision.single); for $(D_KEYWORD double) - to + * $(D_INLINECODE IEEEPrecision.double). It returns different values only + * for $(D_KEYWORD real), since $(D_KEYWORD real) is a platform-dependent type. + * + * If $(D_PARAM F) is a $(D_KEYWORD real) and the target platform isn't + * currently supported, static assertion error will be raised (you can use + * $(D_INLINECODE is(typeof(ieeePrecision!F))) for testing the platform support + * without a compilation error). + * + * Params: + * F = Type to be tested. + * + * Returns: Precision according to IEEE-754. + * + * See_Also: $(D_PSYMBOL IEEEPrecision). + */ +template ieeePrecision(F) +if (isFloatingPoint!F) +{ + static if (F.sizeof == float.sizeof) + { + enum IEEEPrecision ieeePrecision = IEEEPrecision.single; + } + else static if (F.sizeof == double.sizeof) + { + enum IEEEPrecision ieeePrecision = IEEEPrecision.double_; + } + else version (X86) + { + enum IEEEPrecision ieeePrecision = IEEEPrecision.extended; + } + else version (X86_64) + { + enum IEEEPrecision ieeePrecision = IEEEPrecision.extended; + } + else + { + static assert(false, "Unsupported IEEE 754 precision"); + } +} + +/** + * Calculates the absolute value of a number. + * + * Params: + * I = Value type. + * x = Value. + * + * Returns: Absolute value of $(D_PARAM x). + */ +I abs(I)(I x) +if (isIntegral!I) +{ + static if (isSigned!I) + { + return x >= 0 ? x : -x; + } + else + { + return x; + } +} + +/// +pure nothrow @safe @nogc unittest +{ + int i = -1; + assert(i.abs == 1); + static assert(is(typeof(i.abs) == int)); + + uint u = 1; + assert(u.abs == 1); + static assert(is(typeof(u.abs) == uint)); +} + +version (D_Ddoc) +{ + /// ditto + I abs(I)(I x) + if (isFloatingPoint!I); +} +else version (TanyaPhobos) +{ + 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 +{ + float f = -1.64; + assert(f.abs == 1.64F); + static assert(is(typeof(f.abs) == float)); + + double d = -1.64; + assert(d.abs == 1.64); + static assert(is(typeof(d.abs) == double)); + + real r = -1.64; + assert(r.abs == 1.64L); + static assert(is(typeof(r.abs) == real)); +} + +/// ditto +I abs(I : Integer)(const auto ref I x) +{ + auto result = Integer(x, x.allocator); + result.sign = Sign.positive; + return result; +} + +/// ditto +I abs(I : Integer)(I x) +{ + x.sign = Sign.positive; + return x; +} diff --git a/source/tanya/math/package.d b/source/tanya/math/package.d index 0f3e8ea..86f1158 100644 --- a/source/tanya/math/package.d +++ b/source/tanya/math/package.d @@ -15,6 +15,7 @@ module tanya.math; public import tanya.math.mp; +public import tanya.math.nbtheory; public import tanya.math.random; import tanya.meta.trait; @@ -197,33 +198,3 @@ private pure nothrow @safe @nogc unittest assert(899809363.isPseudoprime); assert(982451653.isPseudoprime); } - -/** - * Calculates the absolute value of a number. - * - * Params: - * I = Value type. - * x = Value. - * - * Returns: Absolute value of $(D_PARAM x). - */ -I abs(I : Integer)(const auto ref I x) -{ - auto result = Integer(x, x.allocator); - result.sign = Sign.positive; - return result; -} - -/// Ditto. -I abs(I : Integer)(I x) -{ - x.sign = Sign.positive; - return x; -} - -/// Ditto. -I abs(I)(const I x) -if (isIntegral!I) -{ - return x >= 0 ? x : -x; -}