I want to check code inside math library function sqrt() how is it possible? I am using DEV C++ .
This stuff gets compiled into the toolchain runtime, but since GCC and its Windows port MinGW (which is what your Dev-C++ IDE invokes) are open-source, you can just take a look at the source.
Here it is for latest MinGW GCC; both versions appear to defer basically all of the work to the processor (which is not a great surprise, seeing as x86 — by way of the x87 part of the instruction set — supports square root calculations natively).
long double values
#include <math.h>
#include <errno.h>
extern long double __QNANL;
long double
sqrtl (long double x)
{
if (x < 0.0L )
{
errno = EDOM;
return __QNANL;
}
else
{
long double res;
asm ("fsqrt" : "=t" (res) : "0" (x));
return res;
}
}
float values
#include <math.h>
#include <errno.h>
extern float __QNANF;
float
sqrtf (float x)
{
if (x < 0.0F )
{
errno = EDOM;
return __QNANF;
}
else
{
float res;
asm ("fsqrt" : "=t" (res) : "0" (x));
return res;
}
}
Square roots are calculated by the floating point unit of the processor so there is not much C++ to learn there...
EDIT:
x86 instructions
http://en.wikipedia.org/wiki/X86_instruction_listings
http://en.wikipedia.org/wiki/X87
FSQRT - Square root
Even back in the day: en.wikipedia.org/wiki/8087
If there's no source code for your sqrt(), you can always disassemble it. Inspecting the code would be one type of checking.
You can also write a test for sqrt(). That would be the other type of checking.
Related
I am wondering why I am observering different results when using pow on x86 and x64 respectively. In our application we control the floating point rounding mode, which has worked fine on both Windows and Linux 32 bit.
#include <cmath>
#include <cstdio>
#include <cfloat>
void checkEqual(double expected, double observed) {
if (expected == observed) {
printf("Expected %.23f, got %.23f\n", expected, observed);
}
else {
printf("ERROR: Expected %.23f, got %.23f\n", expected, observed);
}
}
int main(int argc, char **argv) {
unsigned ret, tmp;
_controlfp_s(&ret, 0, 0);
_controlfp_s(&tmp, RC_DOWN, MCW_RC);
checkEqual(2048.0, pow(2.0, 11.0));
checkEqual(0.125, pow(2.0, -3.0));
return 0;
}
Compiling and running with Visual Studio 2015 (2012 gives the same result) gives me the following output
x86:
Expected 2048.00000000000000000000000, got 2048.00000000000000000000000
Expected 0.12500000000000000000000, got 0.12500000000000000000000
x64:
ERROR: Expected 2048.00000000000000000000000, got 2047.99999999999977262632456
ERROR: Expected 0.12500000000000000000000, got 0.12499999999999998612221
Can anyone explain the differences? I know that inherently, floating point calculations are not exact, but for these specific values, I would expect the function to produce the same result regardless of rounding mode.
I investigated this some more and found that the real issue is not how pow is implemented but rather that x86 and x64 hardware are different as Hans Passant suggested.
There are many different implementations of pow possible. For instance, pow(x,y) is exp(y*ln(x)). As you can imagine, exp(11.0*ln(2.0)) can suffer from internal rounding errors even though x and y are exactly representable.
However, it's quite common to call pow with integer arguments, and therefore some libraries have optimized paths for those cases. E.g., pow(x,2*n) is pow(x,n) squared, and pow(x, 2n+1) is x*pow(x, 2n).
It seems your x86 and x64 implementations differ in this respect. That can happen. IEEE only promises precise results for +-*/ and sqrt.
I have an application where I absolutely must use long double data type due to catastrophic truncation error when doing math with double precision. My testing procedures are going crazy because on windows long double with Visual Studio is just an alias to double, while on linux and OSX, long double is a real long double with nominally precision of 1e-19.
On mingw (windows port of GCC) is where I am confused. Mingw claims that LDBL_EPSILON has a precision of 1e-19, but googleing suggests that the mingw uses the c runtime that is actually just the microsoft c runtime which doesn't support real long doubles. Can anyone shed any light here?
EDIT: The crux of the problem is this: on mingw, if I call the math function log(long double x), is this just an alias to log(double x)? In either case, how could I write my own script to test this behavior and/or test for it?
Following code
#include <iostream>
#include <cmath>
int main(void)
{
long double y = 2.0L;
std::cout << sizeof(y) << std::endl;
long double q = sqrt(y);
std::cout << q << std::endl;
return 0;
}
produced output 16 1.41421, so far so good
Ran it throw preprocessor (-E option) and found out that internal, but different from double sqrt() function were called
using ::sqrt;
inline constexpr float sqrt(float __x)
{ return __builtin_sqrtf(__x); }
inline constexpr long double sqrt(long double __x)
{ return __builtin_sqrtl(__x); }
Same for log(), sin(), you name it
Thus, I believe MinGW support long double format in arithmetics as well as in math.functions, and this support is built-in, not libquadmath based
Just tried with MinGW (MinGW distro from nuwen, gcc/g++ 4.9.1, 64bit)
Following program
#include <iostream>
int main(void)
{
double x = 1.0;
long double y = 2.0L;
std::cout << sizeof(x) << std::endl;
std::cout << sizeof(y) << std::endl;
}
produced
8
16
I would guess, long double is supported and is different from standard double, thus
your computations might produce desired result
I've heard there are problems with printing long doubles on Windows due to using MS old runtime.
You might have to use casts or roll your own output routines
Sample code which is valid and gets compiled by gcc but not by VS compiler:
#include <cmath>
int main()
{
float x = 1233.23;
x = round (x * 10) / 10;
return 0;
}
but for some reason, when I am compiling this in Visual Studio I get an error:
C3861: 'round': identifier not found
I do include even cmath as someone suggested here: http://www.daniweb.com/software-development/cpp/threads/270269/boss_loken.cpp147-error-c3861-round-identifier-not-found
Is this function in gcc only?
First of all, cmath is not guaranteed to bring round into the global namespace, so your code could fail, even with an up-to-date, standards compliant C or C++ implementation. To be sure, use std::round (or #include <math.h>.)
Note that your C++ compiler must support C++11 for std::round (<cmath>). A C compiler should support C99 for round (from <math.h>.) If your version of MSVC doesn't work after the fix I suggested, it could simply be that that particular version is pre-C++11, or is simply not standards compliant.
You also can use a boost library:
#include <boost/math/special_functions/round.hpp>
const double a = boost::math::round(3.45); // = 3.0
const int b = boost::math::iround(3.45); // = 3
Visual Studio 2010 (C99) doesn't support round but ceil and floor functions, so you may want to add your own function like;
long long int round(float a)
{
long long int result;
if (a-floor(a)>=0.5)
result = floor(a)+1;
else
result = floor(a);
return result;
};
The std::round nor #include <math.h> supported at the VS 2010 according to my experience.
I would use floor twice to get the correct rounded value,
long long int round(float a)
{
long long int result = (long long int)floor(a);
return result + (long long int)floor((a-result)*2)
};
I found a tutorial about making your first C++ DLL, which I wanted to try by making a function that calculates the octave number of a certain frequency. I first tried the example function, multiplying two values, and that worked. Then I put my calculating function, which I first tested in a standard c++ project, in the DLL code. Now when I want to call the function in Game Maker, it gives me this popup and when I click the OK button the program hangs.
Does anyone have an idea what could cause this access violation?
Compiler information: I am using NetBeans IDE 7.3 in combination with Cygwin 4 (gcc).
Compiled and tested on Windows 7.
DLL code:
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <string>
#include <cmath>
#include <cstdio>
#include <windows.h>
#define GMEXPORT extern "C" __declspec (dllexport)
double A440 = 440;
GMEXPORT double __cdecl SampleFunction(double a, double b) {
return a * b;
}
GMEXPORT int __cdecl freqGetOctave(double f) {
double a = 12*log2(f/(A440/16))+.505;
int c = (int)(a+9)/12;
return c;
}
Game Maker code:
//script: dll_init
globalvar _exmpl,_freq;
var dll_name;
dll_name = "c:\Users\<me>\Documents\NetBeansProjects\GMDLLtest\dist\Debug\Cygwin_4.x-Windows\libGMDLLtest.dll";
_exmpl = external_define(dll_name, "SampleFunction", dll_cdecl, ty_real, 2, ty_real, ty_real);
_freq = external_define(dll_name, "freqGetOctave", dll_cdecl, ty_real, 1, ty_real);
//script: example
return external_call(_exmpl,argument0,argument1);
//script: freq_octave
return external_call(_freq,argument0);
//Watch Excpressions in Debug Screen:
example(3,3) 9
freq_octave(440) [error popped up:]
// [Access violation at address 00405B33 in module 'DLLtest.exe'.
// Read of access 00000004.]
Regarding these exported functions:
Plug-in functions must have a specific format. They can have between 0 and 16 arguments, each of which can either be a real number (double in C) or a null-terminated string. (For more than 4 arguments, only real arguments are supported at the moment.) They must return either a real or a null-terminated string.
Yours returns an integer, not a double. Game Maker will be trying to interpret that integer as a double, which does not go well.
http://gamemaker.info/en/manual/414_00_dlls
I'm normally good at googling stuff like this but I can't seem to find anything this time.
I downloaded some source code from here and it uses a function called roundf.
I already have #include <math.h> and as a first thought added #include <cmath> but still have the problem. I can't seem to find out where the function originates...
Is there an alternative function? Or does anyone know where it comes from so I can include the header file?
The roundf() function is defined by C99, but MSVC implements very little of C99, so it is not available with the Microsoft compilers.
You can use this one:
float roundf(float x)
{
return x >= 0.0f ? floorf(x + 0.5f) : ceilf(x - 0.5f);
}
You also can use a boost library:
#include <boost/math/special_functions/round.hpp>
const double a = boost::math::round(3.45); // = 3.0
const int b = boost::math::iround(3.45); // = 3