Git Product home page Git Product logo

gcem's People

Contributors

gamestrap avatar jonathansharman avatar kthohr avatar marcizhu avatar marekknapek avatar orionserup avatar pkeir avatar sj avatar unicode-hater avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gcem's Issues

gcem::internal::tan_begin infinite loop

In tan_begin:

template<typename T>
constexpr
T
tan_begin(const T x)
{   // tan(x) = tan(x + pi)
    return( x > T(GCEM_PI) ? \
            // if
                tan_begin( x - T(GCEM_PI) * (int)(x/T(GCEM_PI)) ) :
            // else 
                tan_cf_main(x) );
}

The cast

(int)(x/T(GCEM_PI))

can overflow and lead to an infinite loop.

_copysign cannot be used in constant context (MSVC 16 2019)

Building GCEM in a project using Cmake on Windows 10, and with MSVC 16 2019 as the compiler fails, it appears that the implementation of _copysign cannot be used in a constant context. Many errors were thrown of the form:

C:\Users\61405\source\repos\BGNC\extern\gcem\include\gcem_incl/neg_zero.hpp(34,31): message : see usage of '_copysign' [C:\Users\61405\source\repos\BGNC\build\tests\BGNCTestExec.vcxproj]
C:\Users\61405\source\repos\BGNC\tests\coordinates_tests\earth_tests.cpp(129,28): error C2131: expression did not evaluate to a constant [C:\Users\61405\source\repos\BGNC\build\tests\BGNCTestExec.vcxproj]
C:\Users\61405\source\repos\BGNC\extern\gcem\include\gcem_incl/neg_zero.hpp(34,31): message : failure was caused by call of undefined function or one not declared 'constexpr' [C:\Users\61405\source\repos\BGNC\build\tests\BGNCTestExec.vcxproj]

The same code compiled fine when using GCC.

I've confirmed that the errors are removed by manually implementing a version of copysign:

#gcem_options.hpp

template <typename T>
constexpr T HACK_MSVCcopysign(T x, T y)
{
    if ((x < 0 && y > 0) || (x > 0 && y < 0))
    {
        return -x;
    }
    return x;
}

#ifdef _MSC_VER
    #ifndef GCEM_SIGNBIT
        #define GCEM_SIGNBIT(x) _signbit(x)
    #endif
    #ifndef GCEM_COPYSIGN
        // #define GCEM_COPYSIGN(x,y) _copysign(x,y)
        #define GCEM_COPYSIGN(x,y) HACK_MSVCcopysign(x, y)
    #endif
...

Check for C++ 11 compiler fails for x86_64-w64-mingw32-g++

The check for a C++ 11 compiler fails when using x86_64-w64-mingw32-g++ (Version : v11.2.1 20211019)

-- GCE-Math version 1.16.0
-- Performing Test COMPILER_SUPPORTS_CXX11
-- Performing Test COMPILER_SUPPORTS_CXX11 - Failed
CMake Error at build/_deps/gcem-src/CMakeLists.txt:50 (message):
  Unsupported compiler /usr/lib64/ccache/x86_64-w64-mingw32-g++ GCEM requires
  a C++11-compatible compiler.

round(), floor() and ceil() for big numbers

The following code doesn't compile:

constexpr long double const a = 42e32;
constexpr auto const f = gcem::round(a);

My g++-7.4.0 gives me:

file.cpp: In function ‘int main()’:
file.cpp:49:38:   in constexpr expansion of ‘gcem::round<long double>(4.20000000000000011729e+33l)’
./../include/gcem_incl/round.hpp:70:33:   in constexpr expansion of ‘gcem::internal::round_check<long double>(((long double)x))’
./../include/gcem_incl/round.hpp:52:35:   in constexpr expansion of ‘gcem::internal::round_int<long double>(gcem::abs<long double>(((long double)x)))’
./../include/gcem_incl/round.hpp:33:37:   in constexpr expansion of ‘gcem::internal::find_whole<long double>(((long double)x))’
./../include/gcem_incl/find_whole.hpp:37:42:   in constexpr expansion of ‘gcem::internal::floor_check<long double>(((long double)x))’
file.cpp:49:40: error: overflow in constant expression [-fpermissive]
  constexpr auto const f = gcem::round(a);
                                        ^
file.cpp:49:40: error: overflow in constant expression [-fpermissive]
file.cpp:49:40: error: overflow in constant expression [-fpermissive]

The same is true if you replace round with floor or ceil.

I think it should at least be documented that these functions will fail if the input is outside of the bounds of a long long int. Alternatively, maybe it is possible to fall back to a different algorithm for large numbers or deduce that all numbers larger than std::numeric_limits<long long int>::max() are integers anyway (this might at least be true for the smaller floating point types like float, I didn't check). In the latter case, it would be fine to just return the input unmodified.

Trigonometric functions precision

Hi, I like your library, but I cannot find any information about precision guarantees.

In my program, I need a precomputed lookup table of some angles. Before I discovered your library I computed the values at run-time and copy & pasted them into my source. After I discovered your library I wanted to assert, that my precomputed table values match constexpr computation from your library. And this test failed.

I noticed, that your computation are sometimes off by one at last significant place. So, I wanted to ask what precision do you guarantee? Is this a bug or is this (sometimes off by one at ULP) intended behavior? Or maybe it is not possible to compute trigonometric functions precisely at compile-time at all?

I created a little test program, it computes sin and cos of all angles from -15 to +15 degrees, stepping by one degree. I compiled it on Ubuntu 18.04 using GCC/G++ 10, and on Windows using Visual Studio 2019 (19.27.29112).

Best regards, Marek.

The program:

#include <cmath>
#include <cstdio>
#include <numbers>

#include <gcem.hpp>

int main()
{
	static constexpr auto const deg_to_rad = [](double const& deg) -> double { return deg * (std::numbers::pi_v<double> / 180.0); };
	for(int i = -15; i != 15 + 1; ++i)
	{
		std::printf("std::cos (%+3d deg) == %.30f (%a)\n", i, std::cos(deg_to_rad(i)), std::cos(deg_to_rad(i)));
		std::printf("gcem::cos(%+3d deg) == %.30f (%a)%s\n", i, gcem::cos(deg_to_rad(i)), gcem::cos(deg_to_rad(i)), std::cos(deg_to_rad(i)) == gcem::cos(deg_to_rad(i)) ? "" : " bug");
	}
	for(int i = -15; i != 15 + 1; ++i)
	{
		std::printf("std::sin (%+3d deg) == %.30f (%a)\n", i, std::sin(deg_to_rad(i)), std::sin(deg_to_rad(i)));
		std::printf("gcem::sin(%+3d deg) == %.30f (%a)%s\n", i, gcem::sin(deg_to_rad(i)), gcem::sin(deg_to_rad(i)), std::sin(deg_to_rad(i)) == gcem::sin(deg_to_rad(i)) ? "" : " bug");
	}
}

Compile on Ubuntu:

g++-10 -std=c++20 gcem_trig_check.cpp

Output on Ubuntu:

std::cos (-15 deg) == 0.965925826289068312213714762038 (0x1.ee8dd4748bf15p-1)
gcem::cos(-15 deg) == 0.965925826289068312213714762038 (0x1.ee8dd4748bf15p-1)
std::cos (-14 deg) == 0.970295726275996472942608761514 (0x1.f0ca99f79ba25p-1)
gcem::cos(-14 deg) == 0.970295726275996583964911224029 (0x1.f0ca99f79ba26p-1) bug
std::cos (-13 deg) == 0.974370064785235245885530730447 (0x1.f2e0a214e870fp-1)
gcem::cos(-13 deg) == 0.974370064785235245885530730447 (0x1.f2e0a214e870fp-1)
std::cos (-12 deg) == 0.978147600733805688832944724709 (0x1.f4cfc327a008p-1)
gcem::cos(-12 deg) == 0.978147600733805577810642262193 (0x1.f4cfc327a007fp-1) bug
std::cos (-11 deg) == 0.981627183447663975712771389226 (0x1.f697d6938b6c2p-1)
gcem::cos(-11 deg) == 0.981627183447663975712771389226 (0x1.f697d6938b6c2p-1)
std::cos (-10 deg) == 0.984807753012208020315654266597 (0x1.f838b8c811c17p-1)
gcem::cos(-10 deg) == 0.984807753012208131337956729112 (0x1.f838b8c811c18p-1) bug
std::cos ( -9 deg) == 0.987688340595137770350220307591 (0x1.f9b24942fe45cp-1)
gcem::cos( -9 deg) == 0.987688340595137659327917845076 (0x1.f9b24942fe45bp-1) bug
std::cos ( -8 deg) == 0.990268068741570361979142944620 (0x1.fb046a930947ap-1)
gcem::cos( -8 deg) == 0.990268068741570473001445407135 (0x1.fb046a930947bp-1) bug
std::cos ( -7 deg) == 0.992546151641321983127852490725 (0x1.fc2f025a23e8bp-1)
gcem::cos( -7 deg) == 0.992546151641322094150154953240 (0x1.fc2f025a23e8cp-1) bug
std::cos ( -6 deg) == 0.994521895368273289861349439889 (0x1.fd31f94f867c6p-1)
gcem::cos( -6 deg) == 0.994521895368273289861349439889 (0x1.fd31f94f867c6p-1)
std::cos ( -5 deg) == 0.996194698091745545198705258372 (0x1.fe0d3b41815a2p-1)
gcem::cos( -5 deg) == 0.996194698091745434176402795856 (0x1.fe0d3b41815a1p-1) bug
std::cos ( -4 deg) == 0.997564050259824197652847033169 (0x1.fec0b7170fff6p-1)
gcem::cos( -4 deg) == 0.997564050259824197652847033169 (0x1.fec0b7170fff6p-1)
std::cos ( -3 deg) == 0.998629534754573833232882407174 (0x1.ff4c5ed12e61dp-1)
gcem::cos( -3 deg) == 0.998629534754573833232882407174 (0x1.ff4c5ed12e61dp-1)
std::cos ( -2 deg) == 0.999390827019095762118183756684 (0x1.ffb0278bf0567p-1)
gcem::cos( -2 deg) == 0.999390827019095651095881294168 (0x1.ffb0278bf0566p-1) bug
std::cos ( -1 deg) == 0.999847695156391269577511593525 (0x1.ffec097f5af8ap-1)
gcem::cos( -1 deg) == 0.999847695156391158555209131009 (0x1.ffec097f5af89p-1) bug
std::cos ( +0 deg) == 1.000000000000000000000000000000 (0x1p+0)
gcem::cos( +0 deg) == 1.000000000000000000000000000000 (0x1p+0)
std::cos ( +1 deg) == 0.999847695156391269577511593525 (0x1.ffec097f5af8ap-1)
gcem::cos( +1 deg) == 0.999847695156391158555209131009 (0x1.ffec097f5af89p-1) bug
std::cos ( +2 deg) == 0.999390827019095762118183756684 (0x1.ffb0278bf0567p-1)
gcem::cos( +2 deg) == 0.999390827019095651095881294168 (0x1.ffb0278bf0566p-1) bug
std::cos ( +3 deg) == 0.998629534754573833232882407174 (0x1.ff4c5ed12e61dp-1)
gcem::cos( +3 deg) == 0.998629534754573833232882407174 (0x1.ff4c5ed12e61dp-1)
std::cos ( +4 deg) == 0.997564050259824197652847033169 (0x1.fec0b7170fff6p-1)
gcem::cos( +4 deg) == 0.997564050259824197652847033169 (0x1.fec0b7170fff6p-1)
std::cos ( +5 deg) == 0.996194698091745545198705258372 (0x1.fe0d3b41815a2p-1)
gcem::cos( +5 deg) == 0.996194698091745434176402795856 (0x1.fe0d3b41815a1p-1) bug
std::cos ( +6 deg) == 0.994521895368273289861349439889 (0x1.fd31f94f867c6p-1)
gcem::cos( +6 deg) == 0.994521895368273289861349439889 (0x1.fd31f94f867c6p-1)
std::cos ( +7 deg) == 0.992546151641321983127852490725 (0x1.fc2f025a23e8bp-1)
gcem::cos( +7 deg) == 0.992546151641322094150154953240 (0x1.fc2f025a23e8cp-1) bug
std::cos ( +8 deg) == 0.990268068741570361979142944620 (0x1.fb046a930947ap-1)
gcem::cos( +8 deg) == 0.990268068741570473001445407135 (0x1.fb046a930947bp-1) bug
std::cos ( +9 deg) == 0.987688340595137770350220307591 (0x1.f9b24942fe45cp-1)
gcem::cos( +9 deg) == 0.987688340595137659327917845076 (0x1.f9b24942fe45bp-1) bug
std::cos (+10 deg) == 0.984807753012208020315654266597 (0x1.f838b8c811c17p-1)
gcem::cos(+10 deg) == 0.984807753012208131337956729112 (0x1.f838b8c811c18p-1) bug
std::cos (+11 deg) == 0.981627183447663975712771389226 (0x1.f697d6938b6c2p-1)
gcem::cos(+11 deg) == 0.981627183447663975712771389226 (0x1.f697d6938b6c2p-1)
std::cos (+12 deg) == 0.978147600733805688832944724709 (0x1.f4cfc327a008p-1)
gcem::cos(+12 deg) == 0.978147600733805577810642262193 (0x1.f4cfc327a007fp-1) bug
std::cos (+13 deg) == 0.974370064785235245885530730447 (0x1.f2e0a214e870fp-1)
gcem::cos(+13 deg) == 0.974370064785235245885530730447 (0x1.f2e0a214e870fp-1)
std::cos (+14 deg) == 0.970295726275996472942608761514 (0x1.f0ca99f79ba25p-1)
gcem::cos(+14 deg) == 0.970295726275996583964911224029 (0x1.f0ca99f79ba26p-1) bug
std::cos (+15 deg) == 0.965925826289068312213714762038 (0x1.ee8dd4748bf15p-1)
gcem::cos(+15 deg) == 0.965925826289068312213714762038 (0x1.ee8dd4748bf15p-1)
std::sin (-15 deg) == -0.258819045102520739476403832668 (-0x1.0907dc193069p-2)
gcem::sin(-15 deg) == -0.258819045102520739476403832668 (-0x1.0907dc193069p-2)
std::sin (-14 deg) == -0.241921895599667730047954705697 (-0x1.ef74bf2e4b91dp-3)
gcem::sin(-14 deg) == -0.241921895599667730047954705697 (-0x1.ef74bf2e4b91dp-3)
std::sin (-13 deg) == -0.224951054343865003426472526371 (-0x1.ccb3236cdc675p-3)
gcem::sin(-13 deg) == -0.224951054343864975670896910742 (-0x1.ccb3236cdc674p-3) bug
std::sin (-12 deg) == -0.207911690817759342575499204031 (-0x1.a9cd9ac4258f6p-3)
gcem::sin(-12 deg) == -0.207911690817759314819923588402 (-0x1.a9cd9ac4258f5p-3) bug
std::sin (-11 deg) == -0.190808995376544804356555573577 (-0x1.86c6ddd76624fp-3)
gcem::sin(-11 deg) == -0.190808995376544804356555573577 (-0x1.86c6ddd76624fp-3)
std::sin (-10 deg) == -0.173648177666930331186634361984 (-0x1.63a1a7e0b7389p-3)
gcem::sin(-10 deg) == -0.173648177666930358942209977613 (-0x1.63a1a7e0b738ap-3) bug
std::sin ( -9 deg) == -0.156434465040230868959625354364 (-0x1.4060b67a85375p-3)
gcem::sin( -9 deg) == -0.156434465040230868959625354364 (-0x1.4060b67a85375p-3)
std::sin ( -8 deg) == -0.139173100960065437847745783984 (-0x1.1d06c968d9e19p-3)
gcem::sin( -8 deg) == -0.139173100960065465603321399612 (-0x1.1d06c968d9e1ap-3) bug
std::sin ( -7 deg) == -0.121869343405147476100403025612 (-0x1.f32d44c4f62d3p-4)
gcem::sin( -7 deg) == -0.121869343405147489978190833426 (-0x1.f32d44c4f62d4p-4) bug
std::sin ( -6 deg) == -0.104528463267653470847307062286 (-0x1.ac2609b3c576cp-4)
gcem::sin( -6 deg) == -0.104528463267653456969519254471 (-0x1.ac2609b3c576bp-4) bug
std::sin ( -5 deg) == -0.087155742747658165869850677154 (-0x1.64fd6b8c28102p-4)
gcem::sin( -5 deg) == -0.087155742747658151992062869340 (-0x1.64fd6b8c28101p-4) bug
std::sin ( -4 deg) == -0.069756473744125302438590097154 (-0x1.1db8f6d6a5128p-4)
gcem::sin( -4 deg) == -0.069756473744125302438590097154 (-0x1.1db8f6d6a5128p-4)
std::sin ( -3 deg) == -0.052335956242943834637593170100 (-0x1.acbc748efc90ep-5)
gcem::sin( -3 deg) == -0.052335956242943834637593170100 (-0x1.acbc748efc90ep-5)
std::sin ( -2 deg) == -0.034899496702500969191884649945 (-0x1.1de58c9f7dc27p-5)
gcem::sin( -2 deg) == -0.034899496702500969191884649945 (-0x1.1de58c9f7dc27p-5)
std::sin ( -1 deg) == -0.017452406437283511653202339176 (-0x1.1df0b2b89dd1ep-6)
gcem::sin( -1 deg) == -0.017452406437283511653202339176 (-0x1.1df0b2b89dd1ep-6)
std::sin ( +0 deg) == 0.000000000000000000000000000000 (0x0p+0)
gcem::sin( +0 deg) == 0.000000000000000000000000000000 (0x0p+0)
std::sin ( +1 deg) == 0.017452406437283511653202339176 (0x1.1df0b2b89dd1ep-6)
gcem::sin( +1 deg) == 0.017452406437283511653202339176 (0x1.1df0b2b89dd1ep-6)
std::sin ( +2 deg) == 0.034899496702500969191884649945 (0x1.1de58c9f7dc27p-5)
gcem::sin( +2 deg) == 0.034899496702500969191884649945 (0x1.1de58c9f7dc27p-5)
std::sin ( +3 deg) == 0.052335956242943834637593170100 (0x1.acbc748efc90ep-5)
gcem::sin( +3 deg) == 0.052335956242943834637593170100 (0x1.acbc748efc90ep-5)
std::sin ( +4 deg) == 0.069756473744125302438590097154 (0x1.1db8f6d6a5128p-4)
gcem::sin( +4 deg) == 0.069756473744125302438590097154 (0x1.1db8f6d6a5128p-4)
std::sin ( +5 deg) == 0.087155742747658165869850677154 (0x1.64fd6b8c28102p-4)
gcem::sin( +5 deg) == 0.087155742747658151992062869340 (0x1.64fd6b8c28101p-4) bug
std::sin ( +6 deg) == 0.104528463267653470847307062286 (0x1.ac2609b3c576cp-4)
gcem::sin( +6 deg) == 0.104528463267653456969519254471 (0x1.ac2609b3c576bp-4) bug
std::sin ( +7 deg) == 0.121869343405147476100403025612 (0x1.f32d44c4f62d3p-4)
gcem::sin( +7 deg) == 0.121869343405147489978190833426 (0x1.f32d44c4f62d4p-4) bug
std::sin ( +8 deg) == 0.139173100960065437847745783984 (0x1.1d06c968d9e19p-3)
gcem::sin( +8 deg) == 0.139173100960065465603321399612 (0x1.1d06c968d9e1ap-3) bug
std::sin ( +9 deg) == 0.156434465040230868959625354364 (0x1.4060b67a85375p-3)
gcem::sin( +9 deg) == 0.156434465040230868959625354364 (0x1.4060b67a85375p-3)
std::sin (+10 deg) == 0.173648177666930331186634361984 (0x1.63a1a7e0b7389p-3)
gcem::sin(+10 deg) == 0.173648177666930358942209977613 (0x1.63a1a7e0b738ap-3) bug
std::sin (+11 deg) == 0.190808995376544804356555573577 (0x1.86c6ddd76624fp-3)
gcem::sin(+11 deg) == 0.190808995376544804356555573577 (0x1.86c6ddd76624fp-3)
std::sin (+12 deg) == 0.207911690817759342575499204031 (0x1.a9cd9ac4258f6p-3)
gcem::sin(+12 deg) == 0.207911690817759314819923588402 (0x1.a9cd9ac4258f5p-3) bug
std::sin (+13 deg) == 0.224951054343865003426472526371 (0x1.ccb3236cdc675p-3)
gcem::sin(+13 deg) == 0.224951054343864975670896910742 (0x1.ccb3236cdc674p-3) bug
std::sin (+14 deg) == 0.241921895599667730047954705697 (0x1.ef74bf2e4b91dp-3)
gcem::sin(+14 deg) == 0.241921895599667730047954705697 (0x1.ef74bf2e4b91dp-3)
std::sin (+15 deg) == 0.258819045102520739476403832668 (0x1.0907dc193069p-2)
gcem::sin(+15 deg) == 0.258819045102520739476403832668 (0x1.0907dc193069p-2)

Compile on Windows:

cl /std:c++latest gcem_trig_test.cpp

Output on Windows:

std::cos (-15 deg) == 0.965925826289068312213714762038 (0x1.ee8dd4748bf15p-1)
gcem::cos(-15 deg) == 0.965925826289068312213714762038 (0x1.ee8dd4748bf15p-1)
std::cos (-14 deg) == 0.970295726275996472942608761514 (0x1.f0ca99f79ba25p-1)
gcem::cos(-14 deg) == 0.970295726275996583964911224029 (0x1.f0ca99f79ba26p-1) bug
std::cos (-13 deg) == 0.974370064785235245885530730447 (0x1.f2e0a214e870fp-1)
gcem::cos(-13 deg) == 0.974370064785235245885530730447 (0x1.f2e0a214e870fp-1)
std::cos (-12 deg) == 0.978147600733805688832944724709 (0x1.f4cfc327a0080p-1)
gcem::cos(-12 deg) == 0.978147600733805577810642262193 (0x1.f4cfc327a007fp-1) bug
std::cos (-11 deg) == 0.981627183447663975712771389226 (0x1.f697d6938b6c2p-1)
gcem::cos(-11 deg) == 0.981627183447663975712771389226 (0x1.f697d6938b6c2p-1)
std::cos (-10 deg) == 0.984807753012208020315654266597 (0x1.f838b8c811c17p-1)
gcem::cos(-10 deg) == 0.984807753012208131337956729112 (0x1.f838b8c811c18p-1) bug
std::cos ( -9 deg) == 0.987688340595137770350220307591 (0x1.f9b24942fe45cp-1)
gcem::cos( -9 deg) == 0.987688340595137659327917845076 (0x1.f9b24942fe45bp-1) bug
std::cos ( -8 deg) == 0.990268068741570361979142944620 (0x1.fb046a930947ap-1)
gcem::cos( -8 deg) == 0.990268068741570473001445407135 (0x1.fb046a930947bp-1) bug
std::cos ( -7 deg) == 0.992546151641321983127852490725 (0x1.fc2f025a23e8bp-1)
gcem::cos( -7 deg) == 0.992546151641322094150154953240 (0x1.fc2f025a23e8cp-1) bug
std::cos ( -6 deg) == 0.994521895368273289861349439889 (0x1.fd31f94f867c6p-1)
gcem::cos( -6 deg) == 0.994521895368273289861349439889 (0x1.fd31f94f867c6p-1)
std::cos ( -5 deg) == 0.996194698091745545198705258372 (0x1.fe0d3b41815a2p-1)
gcem::cos( -5 deg) == 0.996194698091745434176402795856 (0x1.fe0d3b41815a1p-1) bug
std::cos ( -4 deg) == 0.997564050259824197652847033169 (0x1.fec0b7170fff6p-1)
gcem::cos( -4 deg) == 0.997564050259824197652847033169 (0x1.fec0b7170fff6p-1)
std::cos ( -3 deg) == 0.998629534754573833232882407174 (0x1.ff4c5ed12e61dp-1)
gcem::cos( -3 deg) == 0.998629534754573833232882407174 (0x1.ff4c5ed12e61dp-1)
std::cos ( -2 deg) == 0.999390827019095762118183756684 (0x1.ffb0278bf0567p-1)
gcem::cos( -2 deg) == 0.999390827019095651095881294168 (0x1.ffb0278bf0566p-1) bug
std::cos ( -1 deg) == 0.999847695156391269577511593525 (0x1.ffec097f5af8ap-1)
gcem::cos( -1 deg) == 0.999847695156391158555209131009 (0x1.ffec097f5af89p-1) bug
std::cos ( +0 deg) == 1.000000000000000000000000000000 (0x1.0000000000000p+0)
gcem::cos( +0 deg) == 1.000000000000000000000000000000 (0x1.0000000000000p+0)
std::cos ( +1 deg) == 0.999847695156391269577511593525 (0x1.ffec097f5af8ap-1)
gcem::cos( +1 deg) == 0.999847695156391158555209131009 (0x1.ffec097f5af89p-1) bug
std::cos ( +2 deg) == 0.999390827019095762118183756684 (0x1.ffb0278bf0567p-1)
gcem::cos( +2 deg) == 0.999390827019095651095881294168 (0x1.ffb0278bf0566p-1) bug
std::cos ( +3 deg) == 0.998629534754573833232882407174 (0x1.ff4c5ed12e61dp-1)
gcem::cos( +3 deg) == 0.998629534754573833232882407174 (0x1.ff4c5ed12e61dp-1)
std::cos ( +4 deg) == 0.997564050259824197652847033169 (0x1.fec0b7170fff6p-1)
gcem::cos( +4 deg) == 0.997564050259824197652847033169 (0x1.fec0b7170fff6p-1)
std::cos ( +5 deg) == 0.996194698091745545198705258372 (0x1.fe0d3b41815a2p-1)
gcem::cos( +5 deg) == 0.996194698091745434176402795856 (0x1.fe0d3b41815a1p-1) bug
std::cos ( +6 deg) == 0.994521895368273289861349439889 (0x1.fd31f94f867c6p-1)
gcem::cos( +6 deg) == 0.994521895368273289861349439889 (0x1.fd31f94f867c6p-1)
std::cos ( +7 deg) == 0.992546151641321983127852490725 (0x1.fc2f025a23e8bp-1)
gcem::cos( +7 deg) == 0.992546151641322094150154953240 (0x1.fc2f025a23e8cp-1) bug
std::cos ( +8 deg) == 0.990268068741570361979142944620 (0x1.fb046a930947ap-1)
gcem::cos( +8 deg) == 0.990268068741570473001445407135 (0x1.fb046a930947bp-1) bug
std::cos ( +9 deg) == 0.987688340595137770350220307591 (0x1.f9b24942fe45cp-1)
gcem::cos( +9 deg) == 0.987688340595137659327917845076 (0x1.f9b24942fe45bp-1) bug
std::cos (+10 deg) == 0.984807753012208020315654266597 (0x1.f838b8c811c17p-1)
gcem::cos(+10 deg) == 0.984807753012208131337956729112 (0x1.f838b8c811c18p-1) bug
std::cos (+11 deg) == 0.981627183447663975712771389226 (0x1.f697d6938b6c2p-1)
gcem::cos(+11 deg) == 0.981627183447663975712771389226 (0x1.f697d6938b6c2p-1)
std::cos (+12 deg) == 0.978147600733805688832944724709 (0x1.f4cfc327a0080p-1)
gcem::cos(+12 deg) == 0.978147600733805577810642262193 (0x1.f4cfc327a007fp-1) bug
std::cos (+13 deg) == 0.974370064785235245885530730447 (0x1.f2e0a214e870fp-1)
gcem::cos(+13 deg) == 0.974370064785235245885530730447 (0x1.f2e0a214e870fp-1)
std::cos (+14 deg) == 0.970295726275996472942608761514 (0x1.f0ca99f79ba25p-1)
gcem::cos(+14 deg) == 0.970295726275996583964911224029 (0x1.f0ca99f79ba26p-1) bug
std::cos (+15 deg) == 0.965925826289068312213714762038 (0x1.ee8dd4748bf15p-1)
gcem::cos(+15 deg) == 0.965925826289068312213714762038 (0x1.ee8dd4748bf15p-1)
std::sin (-15 deg) == -0.258819045102520739476403832668 (-0x1.0907dc1930690p-2)
gcem::sin(-15 deg) == -0.258819045102520739476403832668 (-0x1.0907dc1930690p-2)
std::sin (-14 deg) == -0.241921895599667730047954705697 (-0x1.ef74bf2e4b91dp-3)
gcem::sin(-14 deg) == -0.241921895599667730047954705697 (-0x1.ef74bf2e4b91dp-3)
std::sin (-13 deg) == -0.224951054343865003426472526371 (-0x1.ccb3236cdc675p-3)
gcem::sin(-13 deg) == -0.224951054343864975670896910742 (-0x1.ccb3236cdc674p-3) bug
std::sin (-12 deg) == -0.207911690817759342575499204031 (-0x1.a9cd9ac4258f6p-3)
gcem::sin(-12 deg) == -0.207911690817759314819923588402 (-0x1.a9cd9ac4258f5p-3) bug
std::sin (-11 deg) == -0.190808995376544804356555573577 (-0x1.86c6ddd76624fp-3)
gcem::sin(-11 deg) == -0.190808995376544804356555573577 (-0x1.86c6ddd76624fp-3)
std::sin (-10 deg) == -0.173648177666930331186634361984 (-0x1.63a1a7e0b7389p-3)
gcem::sin(-10 deg) == -0.173648177666930358942209977613 (-0x1.63a1a7e0b738ap-3) bug
std::sin ( -9 deg) == -0.156434465040230868959625354364 (-0x1.4060b67a85375p-3)
gcem::sin( -9 deg) == -0.156434465040230868959625354364 (-0x1.4060b67a85375p-3)
std::sin ( -8 deg) == -0.139173100960065437847745783984 (-0x1.1d06c968d9e19p-3)
gcem::sin( -8 deg) == -0.139173100960065465603321399612 (-0x1.1d06c968d9e1ap-3) bug
std::sin ( -7 deg) == -0.121869343405147476100403025612 (-0x1.f32d44c4f62d3p-4)
gcem::sin( -7 deg) == -0.121869343405147489978190833426 (-0x1.f32d44c4f62d4p-4) bug
std::sin ( -6 deg) == -0.104528463267653470847307062286 (-0x1.ac2609b3c576cp-4)
gcem::sin( -6 deg) == -0.104528463267653456969519254471 (-0x1.ac2609b3c576bp-4) bug
std::sin ( -5 deg) == -0.087155742747658165869850677154 (-0x1.64fd6b8c28102p-4)
gcem::sin( -5 deg) == -0.087155742747658151992062869340 (-0x1.64fd6b8c28101p-4) bug
std::sin ( -4 deg) == -0.069756473744125302438590097154 (-0x1.1db8f6d6a5128p-4)
gcem::sin( -4 deg) == -0.069756473744125302438590097154 (-0x1.1db8f6d6a5128p-4)
std::sin ( -3 deg) == -0.052335956242943834637593170100 (-0x1.acbc748efc90ep-5)
gcem::sin( -3 deg) == -0.052335956242943834637593170100 (-0x1.acbc748efc90ep-5)
std::sin ( -2 deg) == -0.034899496702500969191884649945 (-0x1.1de58c9f7dc27p-5)
gcem::sin( -2 deg) == -0.034899496702500969191884649945 (-0x1.1de58c9f7dc27p-5)
std::sin ( -1 deg) == -0.017452406437283511653202339176 (-0x1.1df0b2b89dd1ep-6)
gcem::sin( -1 deg) == -0.017452406437283511653202339176 (-0x1.1df0b2b89dd1ep-6)
std::sin ( +0 deg) == 0.000000000000000000000000000000 (0x0.0000000000000p+0)
gcem::sin( +0 deg) == 0.000000000000000000000000000000 (0x0.0000000000000p+0)
std::sin ( +1 deg) == 0.017452406437283511653202339176 (0x1.1df0b2b89dd1ep-6)
gcem::sin( +1 deg) == 0.017452406437283511653202339176 (0x1.1df0b2b89dd1ep-6)
std::sin ( +2 deg) == 0.034899496702500969191884649945 (0x1.1de58c9f7dc27p-5)
gcem::sin( +2 deg) == 0.034899496702500969191884649945 (0x1.1de58c9f7dc27p-5)
std::sin ( +3 deg) == 0.052335956242943834637593170100 (0x1.acbc748efc90ep-5)
gcem::sin( +3 deg) == 0.052335956242943834637593170100 (0x1.acbc748efc90ep-5)
std::sin ( +4 deg) == 0.069756473744125302438590097154 (0x1.1db8f6d6a5128p-4)
gcem::sin( +4 deg) == 0.069756473744125302438590097154 (0x1.1db8f6d6a5128p-4)
std::sin ( +5 deg) == 0.087155742747658165869850677154 (0x1.64fd6b8c28102p-4)
gcem::sin( +5 deg) == 0.087155742747658151992062869340 (0x1.64fd6b8c28101p-4) bug
std::sin ( +6 deg) == 0.104528463267653470847307062286 (0x1.ac2609b3c576cp-4)
gcem::sin( +6 deg) == 0.104528463267653456969519254471 (0x1.ac2609b3c576bp-4) bug
std::sin ( +7 deg) == 0.121869343405147476100403025612 (0x1.f32d44c4f62d3p-4)
gcem::sin( +7 deg) == 0.121869343405147489978190833426 (0x1.f32d44c4f62d4p-4) bug
std::sin ( +8 deg) == 0.139173100960065437847745783984 (0x1.1d06c968d9e19p-3)
gcem::sin( +8 deg) == 0.139173100960065465603321399612 (0x1.1d06c968d9e1ap-3) bug
std::sin ( +9 deg) == 0.156434465040230868959625354364 (0x1.4060b67a85375p-3)
gcem::sin( +9 deg) == 0.156434465040230868959625354364 (0x1.4060b67a85375p-3)
std::sin (+10 deg) == 0.173648177666930331186634361984 (0x1.63a1a7e0b7389p-3)
gcem::sin(+10 deg) == 0.173648177666930358942209977613 (0x1.63a1a7e0b738ap-3) bug
std::sin (+11 deg) == 0.190808995376544804356555573577 (0x1.86c6ddd76624fp-3)
gcem::sin(+11 deg) == 0.190808995376544804356555573577 (0x1.86c6ddd76624fp-3)
std::sin (+12 deg) == 0.207911690817759342575499204031 (0x1.a9cd9ac4258f6p-3)
gcem::sin(+12 deg) == 0.207911690817759314819923588402 (0x1.a9cd9ac4258f5p-3) bug
std::sin (+13 deg) == 0.224951054343865003426472526371 (0x1.ccb3236cdc675p-3)
gcem::sin(+13 deg) == 0.224951054343864975670896910742 (0x1.ccb3236cdc674p-3) bug
std::sin (+14 deg) == 0.241921895599667730047954705697 (0x1.ef74bf2e4b91dp-3)
gcem::sin(+14 deg) == 0.241921895599667730047954705697 (0x1.ef74bf2e4b91dp-3)
std::sin (+15 deg) == 0.258819045102520739476403832668 (0x1.0907dc1930690p-2)
gcem::sin(+15 deg) == 0.258819045102520739476403832668 (0x1.0907dc1930690p-2)

Inverse square root

An inverse square root is a rather popular function. Would be nice to have it. Wikipedia suggests a constexpr implementation. Further sections also reference research on better magic number, e.g. 10.1109/JPROC.2020.2991885.

pow with floats fails in cuda

using
constexpr float result = gcem::pow(5,0.5);
fails with the following error:

error: function call must have a constant value in a constant expression
.../external/gcem/gcem_incl/log.hpp(106): note: floating-point values cannot be compared
.../external/gcem/gcem_incl/log.hpp(144): note: called from:
.../external/gcem/gcem_incl/pow.hpp(37): note: called from:
.../external/gcem/gcem_incl/pow.hpp(50): note: called from:
.../external/gcem/gcem_incl/pow.hpp(79): note: called from:

I'm using the nvidia nvcc compiler version 9.1 with gcc 6.5.
Using pow with integers works fine.

C++20 is_constant_evaluated

C++20 comes with a handy is_constant_evaluated which can be used to detect evaluation context.

Essentially, it can allow gcem to be a complete wrapper around stdlib operations (where stdlib is being replaced for compile-time context) and better runtime performance.

Moreover, without depending on C++ version, __cpp_lib_is_constant_evaluated can be used to check if the compiler provides the function (from header <type_traits>)

Before:

template<typename T>
constexpr
return_t<T>
ceil(const T x)
noexcept
{
    return internal::ceil_check( static_cast<return_t<T>>(x) );
}

After:

template<typename T>
constexpr
return_t<T>
ceil(const T x)
noexcept
{
#ifdef __cpp_lib_is_constant_evaluated
    if (!std::is_constant_evaluated()) return std::ceil(static_cast<return_t<T>>(x));
#endif
    return internal::ceil_check( static_cast<return_t<T>>(x) );
}

Benefits:

  • GCEM still remains C++11 compliant, but provides functionality if the compiler can via extensions
  • We can use GCEM without incurring a penalty if a run-time context is used where compile-time was expected

Cons: Slight more code

Incompatibility with math.h

Hi, this is a small thing.
I've inherited inclusion of some macros from <math.h> from some other libraries that I use in a project. The compiler tries to expand in your awesome gcem library, braking the code. An easy fix is to add

#undef abs
#undef round
#undef signbit

just before inclusion of . Looking into , they've done something similar (at least for ARM GCC):

// Get rid of those macros defined in <math.h> in lieu of real functions.
#undef abs
#undef div
#undef acos
#undef asin
#undef atan
#undef atan2
#undef ceil
#undef cos
#undef cosh
#undef exp
#undef fabs
#undef floor
#undef fmod
#undef frexp
#undef ldexp
#undef log
#undef log10
#undef modf
#undef pow
#undef sin
#undef sinh
#undef sqrt
#undef tan
#undef tanh

Maybe this would be an idea for your lib? It'l take you all of 5 seconds to make the change and ensure compatibility with older code bases. Just a thought.

Thanks and have a nice day.

Niels

overflow

there's might** be overflow issues

e.g.
abs function returns x == T(0) ? T(0) : x < T(0) ? - x : x

since abs(min limit) == max_limit + 1
the result for abs(INT64_MIN) is -9223372036854775808 (negative)
INT64_MIN == 0 ? 0 : INT64_MIN < 0 ? -INT64_MIN : INT64_MIN

** = i didn't executed the code since i'm using it as reference

Why gcem is much slower than cmath?

I have some functions in my library that need to be called at both compile-time and runtime, and cmath has varying degrees of support for constexpr on different platforms, so I chose to use gcem.
But in using it, I found that many of gcem's functions are an order of magnitude slower than cmath under O3 optimization. I know that I can write two versions that are called at compile time and at runtime, but I'm wondering why gcem is so much slower at runtime?

1719030925962.png

I've tested this under x86 linux, windows and mac, compiling with g++, msvc and apple clang respectively, and all get roughly the same results.

conda-forge feedstock

Hi @kthohr

Thanks for this package!!

I would like to rely on your wonderful package. Therefore I would also need a conda-forge feedstock. Would you be interested to become a co-maintainer ?

If so please comment "I agree to be a maintainer" in the PR : conda-forge/staged-recipes#14818 .
(If you see this after the PR is merged I will add you to the feedstock!)

sqrt fails for DBL_MAX

gcem::sqrt(DBL_MAX) fails with msvc or clang for the following reason :

failure was caused by evaluation exceeding call depth limit of 512 (/constexpr:depth)

not very important (I can replace the value) but you may have wanted to know

pow(), log(), log2(), log10() broken for small input arguments

First of all, thank you so much for this library! I've been using it to build a compile-time filter design library [1] and it's been working (almost) flawlessly! :)

When using the pow() function with a small base argument to compute n-th roots, I found that it would always return zero.

#include <cmath>
#include <iomanip>
#include <iostream>

#include <gcem.hpp>

int main()
{
    std::cout << std::setprecision(20);
    std::cout << "std::pow():  " << std::pow(1e-20, 1.0/8.0) << "\n";
    std::cout << "gcem::pow(): " << gcem::pow(1e-20, 1.0/8.0) << "\n";
}

This will output:

std::pow():  0.0031622776601683793944
gcem::pow(): 0

So I dug a little deeper and the reason is that log(), which is used to implement pow(), has this check:

            // x ~= 0
            GCLIM<T>::epsilon() > x ? \
                - GCLIM<T>::infinity() :

Now ::epsilon() is typically much larger than the smallest representable floating point number and as a result, log() will always return infinity for small input arguments. The same check is present in log2() and log10().

Replacing this check with a simple check for non-zeroness makes the code work as expected.

[1] Part of libembedded.

Add constexpr clamp function

It would be very handy to have constexpr clamp function here. It isn't avalible at c++11 at all and having math library that would take care of it would be great.

Performance optimisation proposal

I made some preliminary performance benchmarks on Cortex-M3.

sqrt

  • 23% performance gain with -O1
  • 21% performance gain with -Os

Besides the performance gain, the memory requirements are lower and most important deterministic.
This is especially crucial for embedded systems.

That's why I propose to consider loop based calculations instead of recursion based.


arm-none-eabi-gcc (Fedora 13.2.0-5.fc40) 13.2.0

-O1

-mcpu=cortex-m3 -mthumb -O1 -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -ffreestanding

-Os

-mcpu=cortex-m3 -mthumb -Os -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -ffreestanding


sqrt implemented in loop

-O1

sqrt(0.6) =  0.77460: 12448
floor(0.6) =  0.00000: 1272
fabs(0.6) =  0.60000: 212
log(0.6) = -0.51083: 29780
-Os

sqrt(0.6) =  0.77460: 11825
floor(0.6) =  0.00000: 1262
fabs(0.6) =  0.60000: 241
log(0.6) = -0.51083: 29925

sqrt implemented recursively

-O1

sqrt(0.6) =  0.77460: 16359
floor(0.6) =  0.00000: 1265
fabs(0.6) =  0.60000: 207
log(0.6) = -0.51083: 30062
-Os

sqrt(0.6) =  0.77460: 15055
floor(0.6) =  0.00000: 1332
fabs(0.6) =  0.60000: 240
log(0.6) = -0.51083: 29429

incomplete_gamma_inv : Unexpected NaNs for specific values

I tried incomplete_gamma_inv to help me convert a flat random distribution to a gamma-distribution. When I try a large sample most inputs work well, but I get NaNs with some specific values as listed below:

#include <gcem.hpp>
#include <iostream>
#include <vector>

int main()
{
    std::vector<double> r = {2.26397533e-05, 9.99999672e-01, 7.41391908e-04, 3.88840912e-04,
                             7.33291963e-04, 2.62747984e-04, 2.54816143e-04, 1.69432024e-04,
                             1.75788999e-04, 2.59617111e-04, 4.94140433e-04, 6.44463347e-04};

    for (auto& i : r) {
        std::cout << gcem::incomplete_gamma_inv(2.0, i) << std::endl;
    }

    return 0;
}

which gives:

nan
nan
nan
nan
nan
nan
nan
nan
nan
nan
nan
nan

Note that most are quite small, but not even all of them. Do you know what is going on here?

exp.hpp(61,68): warning C4244: 'return': conversion from 'T1' to 'T', possible loss of data

Visual Studio 2019 16.9.6 x86.

#include "c:/dev/repos/github.com/kthohr/gcem/include/gcem.hpp"

int main()
{
    static constexpr float const s_number = 0.5f;
    static constexpr float const s_computation = gcem::exp(s_number);
}
Build started...
1>------ Build started: Project: Project2, Configuration: Debug Win32 ------
1>Source.cpp
1>c:\dev\repos\github.com\kthohr\gcem\include\gcem_incl\exp.hpp(61,68): warning C4244: 'return': conversion from 'T1' to 'T', possible loss of data
1>        with
1>        [
1>            T1=long double
1>        ]
1>        and
1>        [
1>            T=float
1>        ]
1>c:\dev\repos\github.com\kthohr\gcem\include\gcem_incl\exp.hpp(82): message : see reference to function template instantiation 'T gcem::internal::exp_split<T>(const T) noexcept' being compiled
1>        with
1>        [
1>            T=float
1>        ]
1>c:\dev\repos\github.com\kthohr\gcem\include\gcem_incl\exp.hpp(103): message : see reference to function template instantiation 'T gcem::internal::exp_check<float>(const T) noexcept' being compiled
1>        with
1>        [
1>            T=float
1>        ]
1>C:\Users\knapekma\source\repos\Project2\Project2\Source.cpp(13): message : see reference to function template instantiation 'float gcem::exp<float>(const T) noexcept' being compiled
1>        with
1>        [
1>            T=float
1>        ]
1>Done building project "Project2.vcxproj".
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========

Trigonometric functions of large values lose precision

The following program compares gcem::sin with GCC's __builtin_sin for input of the form 2**n with n from 0 to 63. It appears that already for input of 512.0 relative error is more than 5e-13, and for larger input relative error tends to become larger. At input of 2**52 relative error reaches 0.3, and starting from 2**55 the result is simply zero.

I do admit that range reduction is hard to do, but I suggest to at least warn the users (in the README?) that the library is not intended to handle most of the range of the data types it works with.

BTW, why not implement the functions in terms of long double internally (at least when T is a builtin floating-point type)? It would already improve precision, and since it's constexpr, performance is not a problem.

#include <array>
#include <limits>
#include <iomanip>
#include <gcem.hpp>
#include <iostream>

template<unsigned N>
constexpr std::array<double, N> sinPow2_gcem()
{
    static_assert(N<=64);
    std::array<double, N> arr{};
    for(unsigned n=0;n<N;++n)
    {
        arr[n]=gcem::sin(static_cast<double>(1ull<<n));
    }
    return arr;
}

template<unsigned N>
constexpr std::array<double, N> sinPow2_gcc()
{
    static_assert(N<=64);
    std::array<double, N> arr{};
    for(unsigned n=0;n<N;++n)
    {
        arr[n]=__builtin_sin(static_cast<double>(1ull<<n));
    }
    return arr;
}

int main()
{
    constexpr auto table_gcem=sinPow2_gcem<64>();
    constexpr auto table_gcc =sinPow2_gcc <64>();
    for(unsigned n=0;n<table_gcem.size();++n)
    {
        std::cout << std::defaultfloat << "sin(2^" << std::setw(2) << n << ") = "
                  << std::setprecision(std::numeric_limits<double>::max_digits10)
                  << std::setw(21) << table_gcem[n] << " or "
                  << std::setw(21) << table_gcc[n] << ", rel_diff: "
                  << std::scientific << std::setprecision(2)
                  << std::abs((table_gcem[n]-table_gcc[n])/table_gcc[n]) << "\n";
    }
}

Output on my system with GCC version 8.3.0-6ubuntu1~18.04:

sin(2^ 0) =    0.8414709848078965 or    0.8414709848078965, rel_diff: 0.00e+00
sin(2^ 1) =   0.90929742682568182 or   0.90929742682568171, rel_diff: 1.22e-16
sin(2^ 2) =   -0.7568024953079282 or   -0.7568024953079282, rel_diff: 0.00e+00
sin(2^ 3) =   0.98935824662338168 or   0.98935824662338179, rel_diff: 1.12e-16
sin(2^ 4) =  -0.28790331666506591 or   -0.2879033166650653, rel_diff: 2.12e-15
sin(2^ 5) =   0.55142668124169159 or   0.55142668124169059, rel_diff: 1.81e-15
sin(2^ 6) =   0.92002603819679174 or   0.92002603819679063, rel_diff: 1.21e-15
sin(2^ 7) =   0.72103771050172805 or    0.7210377105017316, rel_diff: 4.93e-15
sin(2^ 8) =  -0.99920803410706305 or  -0.99920803410706271, rel_diff: 3.33e-16
sin(2^ 9) =  0.079518494012835325 or  0.079518494012876348, rel_diff: 5.16e-13
sin(2^10) =  -0.15853338004391457 or  -0.15853338004399595, rel_diff: 5.13e-13
sin(2^11) =  -0.31305701278994652 or  -0.31305701279012343, rel_diff: 5.65e-13
sin(2^12) =  -0.59464198760808085 or  -0.59464198760821463, rel_diff: 2.25e-13
sin(2^13) =  -0.95617315284297588 or   -0.9561731528431463, rel_diff: 1.78e-13
sin(2^14) =  -0.55993846566976402 or  -0.55993846566934702, rel_diff: 7.45e-13
sin(2^15) =   0.92785633341405394 or   0.92785633341392471, rel_diff: 1.39e-13
sin(2^16) =   0.69206545382222318 or   0.69206545382272322, rel_diff: 7.23e-13
sin(2^17) =  -0.99911378895071246 or  -0.99911378895077085, rel_diff: 5.84e-14
sin(2^18) = -0.084107027822479849 or -0.084107027809500717, rel_diff: 1.54e-10
sin(2^19) =   0.16761802725644473 or    0.1676180272206543, rel_diff: 2.14e-10
sin(2^20) =   0.33049314009026282 or   0.33049314002173469, rel_diff: 2.07e-10
sin(2^21) =   0.62384439947212311 or   0.62384439935862968, rel_diff: 1.82e-10
sin(2^22) =   0.97512939500607743 or   0.97512939494170703, rel_diff: 6.60e-11
sin(2^23) =   0.43224820173300005 or   0.43224820225679778, rel_diff: 1.21e-09
sin(2^24) =  -0.77956367249015968 or  -0.77956367321777775, rel_diff: 9.33e-10
sin(2^25) =  -0.97651729150386235 or  -0.97651729095092843, rel_diff: 5.66e-10
sin(2^26) =   0.42075989626084753 or   0.42075989775848105, rel_diff: 3.56e-09
sin(2^27) =  -0.76340322666929872 or  -0.76340322880198075, rel_diff: 2.79e-09
sin(2^28) =  -0.98619821358735438 or  -0.98619821183697565, rel_diff: 1.77e-09
sin(2^29) =   0.32656763928319343 or   0.32656766301856333, rel_diff: 7.27e-08
sin(2^30) =  -0.61732637553418868 or  -0.61732641504604213, rel_diff: 6.40e-08
sin(2^31) =  -0.97131013678590572 or  -0.97131017579293921, rel_diff: 4.02e-08
sin(2^32) =  -0.46198671538301844 or  -0.46198657951383493, rel_diff: 2.94e-07
sin(2^33) =   0.81946005342466022 or    0.8194597047356359, rel_diff: 4.26e-07
sin(2^34) =   0.93932460955758246 or   0.93932502694657105, rel_diff: 4.44e-07
sin(2^35) =  -0.64443221186658051 or  -0.64443035102329116, rel_diff: 2.89e-06
sin(2^36) =   0.98554449814305511 or    0.9855441071151041, rel_diff: 3.97e-07
sin(2^37) =   0.33393553242896457 or   0.33393988357522025, rel_diff: 1.30e-05
sin(2^38) =  -0.62953253790928321 or  -0.62953971111701379, rel_diff: 1.14e-05
sin(2^39) =  -0.97826467462457967 or  -0.97826480872807564, rel_diff: 1.37e-07
sin(2^40) =  -0.40568990812427469 or  -0.40570501153282873, rel_diff: 3.72e-05
sin(2^41) =   0.74176170084066606 or   0.74163206513677404, rel_diff: 1.75e-04
sin(2^42) =   0.99494505102476649 or   0.99498379417508209, rel_diff: 3.89e-05
sin(2^43) =  -0.19982643887478732 or  -0.19906887541578028, rel_diff: 3.81e-03
sin(2^44) =   0.39157600746803073 or   0.39016922335187676, rel_diff: 3.61e-03
sin(2^45) =   0.72061401054487106 or   0.71849129172091508, rel_diff: 2.95e-03
sin(2^46) =   0.99925593527723167 or   0.99947305248379947, rel_diff: 2.17e-04
sin(2^47) = -0.077080812954327838 or -0.064884736238273691, rel_diff: 1.88e-01
sin(2^48) =   0.15561499277355606 or   0.12949601773888192, rel_diff: 2.02e-01
sin(2^49) =   0.30743851458038091 or     0.256811307519207, rel_diff: 1.97e-01
sin(2^50) =   0.58509727294046221 or   0.49639651520894085, rel_diff: 1.79e-01
sin(2^51) =   0.94898461935558631 or   0.86183956388130056, rel_diff: 1.01e-01
sin(2^52) =   0.59847214410395666 or   0.87421730262363506, rel_diff: 3.15e-01
sin(2^53) =  -0.95892427466313834 or  -0.84892596481465499, rel_diff: 1.30e-01
sin(2^54) =   0.90929742682568182 or   0.89733475299759258, rel_diff: 1.33e-02
sin(2^55) =                     0 or  -0.79207844079082801, rel_diff: 1.00e+00
sin(2^56) =                     0 or   0.96699996306127067, rel_diff: 1.00e+00
sin(2^57) =                     0 or  -0.49273775680001242, rel_diff: 1.00e+00
sin(2^58) =                     0 or   0.85753897066968443, rel_diff: 1.00e+00
sin(2^59) =                     0 or   0.88226868987759099, rel_diff: 1.00e+00
sin(2^60) =                     0 or  -0.83064921763725463, rel_diff: 1.00e+00
sin(2^61) =                     0 or   0.92500446025316185, rel_diff: 1.00e+00
sin(2^62) =                     0 or  -0.70292244361920886, rel_diff: 1.00e+00
sin(2^63) =                     0 or    0.9999303766734422, rel_diff: 1.00e+00

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.