I want to achieve exactly same floating-point results in a gcc/Linux ported version of a Windows software. For that reason I want all double operations to be of 64-bit precision. This can be done using for example -mpc64 or -msse2 or -fstore-floats (all with side effects). However one thing I can't fix is transcendental functions like sin/asin etc. The docs say that they internally expect (and use I suppose) long double precision and whatever I do they produce results different from Windows counterparts.
How is it possible for these function to calculate results using 64-bit floating point precision?
UPDATE: I was wrong, it is printf("%.17f") that incorrectly rounds the correct double result, "print x" in gdb shows that the number itself is correct. I suppose I need a different question on this one... perhaps on how to make printf not to treat double internally as extended. Maybe using stringstream will give expected results... Yes it does.
Different LibM libraries use different algorithms for elementary functions, so you have to use the same library on both Windows and Linux to achieve exactly the same results. I would suggest to compile FDLibM and statically link it with your software.
I found that it is printf("%.17f") that uses incorrect precision to print results (probably extended internally), when I use stringstream << setprecision(17) the result is correct. So the answer is not really related to the question but, at least it works for me.
But I would be glad if someone provides a way to make printf to produce expected results.
An excellent solution for the transcendental function problem is to use the GNU MPFR Library. But be aware that Microsoft compilers do not support extended precision floating point. With the Microsoft compiler, double and long double are both 53-bit precision. With gcc, long double is 64-bit precision. To get matching results across Windows/linux, you must either avoid use of long double or avoid use of Microsoft compilers. For many Windows projects, the Windows port of gcc (mingw) works well. This lets the Windows project use 64-bit precision long doubles. A problem with mingw long double support is that mingw uses Microsoft libraries for calls such as printf. For that reason, printing a long double doesn't work correctly. A work-around for this problem is to use mpfr_printf.
Related
I am unable to print double value using wsprintf().
I tried sprintf() and it worked fine.
Syntax used for wsprintf() and sprintf() is as follows:
wsprintf(str,TEXT("Square is %lf "),iSquare); // Does not show value
sprintf(str," square is %lf",iSquare); // works okay
Am I making any mistakes while using wsprintf() ?
wsprintf doesn't support floating point. The mistake is using it at all.
If you want something like sprintf, but for wide characters/strings, you want swprintf instead.
Actually, since you're using the TEXT macro, you probably want _stprintf instead though: it'll shift from a narrow to wide implementation in sync with the same preprocessor macros as TEXT uses to decide whether the string will be narrow or wide. This whole approach, however, is largely a relic from the days when Microsoft still sold and supported versions of Windows based on both the 32-bit NT kernel, and on the 16-bit kernel. The 16-bit versions had only extremely minimal wide-character support, so Microsoft worked hard at allowing a single source code base to be compiled to use either narrow characters (targeting 16-bit kernels) or wide characters (to target the 32-bit kernels). The 16-bit kernels have been gone for long enough that almost nobody really has much reason to support them any more.
For what it's worth: wsprintf is almost entirely a historic relic. The w apparently stands for Windows. It was included as part of Windows way back when (back to the 16-bit days). It was written without support for floating point because at that time, Windows didn't use any floating point internally--this is part of why it has routines like MulDiv built-in, even though doing (roughly) the same with floating point is quite trivial.
The function wsprintf() does not support floating point parameters, try using swprintf() instead if you're working with floating point values.
More information about swprint can be found here
wsprintf does not support floating point. See its documentation - lf is not listed as a valid format code.
The swprintf function part of the Visual Studio standard library is what you want. It supports all of the format codes that sprintf does.
Presumably you're not compiled to UNICODE and TEXT is #defined to just a regular string.
I have a file spec (here: http://www.septentrio.com/secure/asterx1v_2_1/SBF%20Reference%20Guide.pdf) that has fields marked as both 32-bit and 64-bit floats (see page 8). How can I use both widths in my program? I am developing on Mac OSX right now but I will also deploy on a Linux machine.
More details:
I know I could tell the compiler the width, but how could I distinguish two different float widths? Maybe someone also has a suggestion for changing the way I parse, which is to reinterpret_cast(buffer+offset) and then use the values. These file sizes are huge (4GB) so I need performance.
This might seem obvious, nevertheless:
On Intel platform and many others float is 32-bit floating point value, and double is 64-bit floating point value. Try this approach. Most likely it will work.
To be absolutely sure check sizeof of your types at the start of your program or statically during compilation if your compiler allows this.
Once again, try the simple solution first.
Float and double arithmetic is both implemented on Intel and it is fast. In any case native arithmetic is the fastest of what you can get from the CPU.
IEEE 754 (http://en.wikipedia.org/wiki/IEEE_floating_point) defines not one floating point format, but several, like 4, 8, 16 bytes, etc. They all have different range and precision but they are all still IEEE values.
I'm working on updating a serialization library to add support for serializing floating point in a portable manner. Ideally I'd like to be able to test the code in an environment where IEEE754 isn't supported. Would it be sufficient to test using a soft-float library? Or any other suggestions about how I can properly test the code?
Free toolchains that you can find for ARM (embedded Linux) development, mostly do not support hard-float operations but soft-float only. You could try with one of these (i.e. CodeSourcery) but you would need some kind of a platform to run the compiled code (real HW or QEMU).
Or if you would want to do the same but on x86 machine, take a look at: Using software floating point on x86 linux
Should your library work on a system where both hardware floating point and soft-float are not available ? If so, if you test using a compiler with soft-float, your code may not compile/work on such a system.
Personally, I would test the library on a ARM9 system with a gcc compiler without soft-float.
Not an answer to your actual question, but describing what you must do to solve the problem.
If you want to support "different" floating point formats, your code would have to understand the internal format of floats [unless you only support "same architecture both ends"], pick the floating point number apart into your own format [which of course may be IEEE-754, but beware of denormals, 128-bit long doubles, NaN, INFINITY, and other "exception values", and of course out of range numbers], and then put it back together to the format required by the other end. If you are not doing this, there is no point in hunting down a non-IEEE-754 system, because it won't work.
Im wondering if atof() can produce a different floating point results based on what compiler is used and what standard libraries are on the machine. Im aware that the conversion is not always accurate due to the way IEEE floats work however im specifically wondering if those outputted IEEE floats will be identical to each other when using various versions of GCC on the same architecture.
Example:
double x = atof("78.93241");
Will x be the same on the same architecture between various GCC versions and various linux distributions (such as GCC 4.1 -> 4.6, RHEL 6.0 and Debian). If not is there anything that documents this behavior?
I see no reason why in the real world atof() wouldn't produce different results with different compilers and/or on different hardware. Even with the same hardware and floating point formats, you can get different results because compilers and libraries can and do have bugs. See, for example, this bug.
I'm trying to get to grips with C++ basics by building a simple arithmetic calculator application. Right now I'm trying to figure out how to make it capable of dealing with integers greater than 4294967295 on 32-bit Windows. I know that Windows' integrated Calculator is capable of this. What have I missed?
Note that this application should be compilable with both MSVC compiler and g++ (MinGW/GCC).
Thank you.
If you want to be both gcc and msvc compatible use <stdint.h>. It's source code compatible with both.
You probably want uint64_t for this. It will get you up to 18,446,744,073,709,551,615.
There are also libraries to get you up to integers as large as you have memory to handle as well.
Use __int64 to get 64-bit int calculations in Visual C++ - not sure if GCC will like this, though.
You could create a header file that typedefs (say) MyInt64 to the appropriate thing for each compiler. Then you can work internally with MyInt64, and the compiled code will be correct for each target. This is a pretty standard way of supporting different target compilers on one source codebase.
afai can tell, long long would work OK for both, but I have not used GCC so YMMV - see here for GCC info and here for Visual C++.
You could also create a "Large Number" class that would basically store the value across multiple variables in one form or another
There are different solutions, if 2^64 is big enough for you, you can use a 64 bit integer type (these are implementation dependent, so search for your particular compiler). On the other hand, if you want to be able to handle any number, you will have to use or implement a BigInteger type that encapsulates it. The implementation is an interesting exercise... basically use a vector of smaller type, operate on each subelement and then merge and normalize the result.