C++ How do you initialize a long double? [duplicate] - c++

I am trying print a simple long double, but it doesn't work
What I tried:
long double ld=5.32;
printf("ld with le = %Le \n",ld);
printf("ld with lf = %Lf \n",ld);
printf("ld with lg = %Lg \n",ld);
Output:
ld with le = -3.209071e-105
ld with lf = -0.000000
ld with lg = -3.20907e-105
With a new value:
ld=6.72;
Output:
ld with le = -1.972024e+111
ld with lf = -1972024235903379200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.000000
ld with lg = -1.97202e+111

There's a similar problem with MinGW under Windows. If that's not what you're using, this answer probably doesn't apply.
The problem is that the compiler (GCC) and the runtime library (Microsoft's) are implemented by different groups that happen to have different ideas about how the type long double should be represented. (gcc uses 128 bits for long double; Microsoft uses 64 bits, with the same representation as double.)
Either choice of representation is perfectly legitimate, but they're incompatible with each other. It's not a bug either in GCC or in Microsoft's library, but in the way MinGW integrates them.
Your options are to use an implementation other than MinGW, to write or copy code that handles long double correctly , or to avoid calling any library functions that take arguments or return results of type long double (computations on long double shouldn't be a problem as long as they don't call any library functions). For example, you can convert to double and print with %g, with some loss of range and precision.
Another (probably better) workaround is to compile with -D__USE_MINGW_ANSI_STDIO, which causes MinGW to use its own implementation of printf and friends rather than relying on the Microsoft implementation.

Related

bcc32c Error integer literal is too large to be represented in any integer type

I have a large __int64 literal:
const __int64 PwTab[] = {
50036500600837093008i64,
3006206760097890820056i64
};
It is accepted nicely by bcc32 (Borland classic compiler) but not by bcc32c (clang).
The error for the clang compiler is:
integer literal is too large to be represented in any integer type
I use the i64 suffix to tell the computer it is a 64bit integer literal.
How can I write an __int64 literal in clang, which is also compatible with the __int64 type in the classic compiler?
As mentioned in the comments the problem was in bcc32 not reporting too large literal during the compile time but silently overflowing which of course created completely different array than expected during runtime.
e.g.
int64_t testVar = 0x112233445566778899aai64;
Which is of course larger than what 64-bit integer can accept and results in runtime value of:
0x33445566778899aa
A sidenote - ll suffix doesn't work in Borland classic compiler. So I have to use i64 in it. But it won't be a problem after switching to clang.

asin produces different answers on different platforms using Clang

#include <cmath>
#include <cstdio>
int main() {
float a = std::asin(-1.f);
printf("%.10f\n", a);
return 0;
}
I ran the code above on multiple platforms using clang, g++ and Visual studio. They all gave me the same answer: -1.5707963705
If I run it on macOS using clang it gives me -1.5707962513.
Clang on macOS is supposed to use libc++, but does macOS has its own implementation of libc++?
If I run clang --verison I get:
Apple LLVM version 10.0.0 (clang-1000.11.45.5)
Target: x86_64-apple-darwin18.0.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
asin is implemented in libm, which is part of the standard C library, not the C++ standard library. (Technically, the C++ standard library includes C library functions, but in practice both the Gnu and the LLVM C++ library implementations rely on the underlying platform math library.) The three platforms -- Linux, OS X and Windows -- each have their own implementation of the math library, so if the library function were being used, it could certainly be a different library function and the result might differ in the last bit position (which is what your test shows).
However, it is quite possible that the library function is never being called in all cases. This will depend on the compilers and the optimization options you pass them (and maybe some other options as well). Since the asin function is part of the standard library and thus has known behaviour, it is entirely legitimate for a compiler to compute the value of std::asin(-1.0F) at compile time, as it would for any other constant expression (like 1.0 + 1.0, which almost any compiler will constant-fold to 2.0 at compile time).
Since you don't mention what optimization settings you are using, it's hard to tell exactly what's going on, but I did a few tests with http://gcc.godbolt.org to get a basic idea:
GCC constant folds the call to asin without any optimisation flags, but it does not precompute the argument promotion in printf (which converts a to a double in order to pass it to printf) unless you specify at least -O1. (Tested with GCC 8.3).
Clang (7.0) calls the standard library function unless you specify at least -O2. However, if you explicitly call asinf, it constant folds at -O1. Go figure.
MSVC (v19.16) does not constant fold. It either calls a std::asin wrapper or directly calls asinf, depending on optimisation settings. I don't really understand what the wrapper does, and I didn't spend much time investigating.
Both GCC and Clang constant fold the expression to precisely the same binary value (0xBFF921FB60000000 as a double), which is the binary value -1.10010010000111111011011 (trailing zeros truncated).
Note that there is also a difference between the printf implementations on the three platforms (printf is also part of the platform C library). In theory, you could see a different decimal output from the same binary value, but since the argument to printf is promoted to double before printf is called and the promotion is precisely defined and not value-altering, it is extremely unlikely that this has any impact in this particular case.
As a side note, if you really care about the seventh decimal point, use double instead of float. Indeed, you should only use float in very specific applications in which precision is unimportant; the normal floating point type is double.
The mathematically exact value of asin(-1) would be -pi/2, which of course is irrational and not possible to represent exactly as a float. The binary digits of pi/2 start with
1.1001001000011111101101010100010001000010110100011000010001101..._2
Your first three libraries round this (correctly) to
1.10010010000111111011011_2 = 1.57079637050628662109375_10
On MacOS it appears to get truncated to:
1.10010010000111111011010_2 = 1.57079625129699707031250_10
This is an error of less than 1 ULP (unit in the last place). This could be caused either by a different implementation, or your FPU is set to a different rounding mode, or perhaps in some cases the compiler computes the value at compile-time.
I don't think the C++ standard really gives any guarantees on the accuracy of transcendental functions.
If you have code which really depends on having (platform/hardware independent) accuracy, I suggest to use a library, like e.g., MPFR. Otherwise, just live with the difference. Or have a look at the source of the asin function which is called in each case.

Transfer programs from one architecture to another

Immediately warn you that this is a difficult task.
There is a test. The test was the result of parsing a large problem to a bug in which we encountered at work. Construction __ attribute__((noinline)) prohibits the compiler to do the substitution function (for optimizations to something there not imploded). This is the easiest way to optimize guaranteed not to kill an interesting situation.
#include <stdio.h>
double d = 5436277361664796672.000000;
long long ll = 5436277361664796253LL;
int __attribute__((noinline))
func1 (void)
{
double d1 = (double)ll;
if (d > d1)
return 1;
else
return 0;
}
int __attribute__((noinline))
func2 (void)
{
if (d > (double)ll)
return 1;
else
return 0;
}
int
main (void)
{
printf ("%d %d\n", func1(), func2());
return 0;
}
I ran this test on intel and sparc. Gcc used in a mode with optimizations and without optimizations. Obtained the following results:
sparc: "gcc" printed "0 0"
sparc: "gcc -O2" printed "0 0"
intel: "gcc" printed "0 1"
intel: "gcc -O2" printed "1 1"
What is the cause differences? Anyway in the analysis situation would be useful to be able to repeat it all myself, but, of course, almost no one has the possibility to run this code on sparc. Instead sparc can try to run under Windows using microsoft or borland C compiler. I do not know what they will be given the results, but in any case something does not match with anything (because we see three different results)
Edit 1
_attribute_ ((noinline)) - an extension of the compiler gcc (forgot to write about it). Therefore VisualStudio can not compile it.
I note that the declaration of the double constant has 19 significant figures which is more precision than can be represented by a IEEE double (which allows 15 to 17 significant figures). So d cannot hold 5436277361664796672.000000 exactly.
The two constant definition strings become different at the 16th digit, so you are in the region where the inaccuracies in the double are of the same magnitude as the difference between these two numbers. Hence the comparison cannot be relied upon.
I do not know if the C++ standard specifies what happens when an over-precise string is converted to a double, but I would not be surprised if the exact result was either undefined or implementation-dependent.
Seems solved the problem. In general, all written correctly. But actually works correctly sparc version. Because standard to convert int64-> float64 must be a loss of precision. And in the code when you convert (for intel) int64-> float80 loss occurs. Ie intel-based code works with higher accuracy , but it is in contradiction with the standard.
Perhaps it is some sort of agreement for the platform Intel, which is permissible by default to work this way. Surely there are some options on which the code runs in strict accordance with the standard (but becomes slower)

long long int on 32-bit Linux vs 64-bit Linux and MPFR

How exactly does a 32-bit Linux system handle long long int compared to 64-bit Linux?
On my 32 bit system I use a C++ wrapper for the MPFR data type; this wrapper has a constructor defined for long int but not long long int. Nevertheless, on the 32-bit system this code just works:
long long int i=5LL;
mpreal myVar(i);
cout<< "this was constructed with a long long int:" <<myVar <<endl;
How is this possible? Does the 32-bit gcc just somehow cast the long long int into say long int for which the mpreal data type does have a constructor? If the above code is run on 64-bit Linux then the compiler results in an error about the construction being ambiguous.
I know that some people will tell me not to use long long int at all on 64 bit, but unfortunately, I'm using another library (odeint) where this is built in to the code to construct my given multiprecision data type this way, so I don't think I can change things.
Is long long int exactly the same as long int on 64-bit anyway? Will I lose data if I cast to long int? e.g. if I make my own constructor like:
mpreal(const long long int u, mp_prec_t prec, mp_rnd_t mode)
{
mpfr_init2(mp,prec);
mpfr_set_si(mp, u, mode);
}
I asked the author of mpreal.h about this (the full answer is at http://www.holoborodko.com/pavel/mpfr/#comment-7444), firstly regarding building a new constructor for long long int on a 64x system:
>Functions “mpfr_set_ui/si” should be fine.
>Basically constructor for “long long int” should be equivalent to “long int” one.
>GNU GCC system makes porting from x32 to x64 a little bit messy. It automatically
>upgrades integer types to x64 bits, which could easily break code being ported.
>The best workaround for GCC would be to use types with explicit number of bits:
>int32_t, int64_t from stdint.h. Then move from x32 to x64 would be painless.
>However neither authors of MPFR nor developers of numeric libraries follow this
>standard using “long long int”, “long int”, “intmax_t” all of which means different
>things on x32 and x64 in GCC world.
>There is some macro-logic in mpreal.h which tries to make things smooth:
>(a) for x32 builds we define additional constructors for int64_t (aka “long long int”
>or “intmax_t” )
>(b) for x64 builds we remove constructors for such type since “long int” is already
>64bit wide.
>Macro MPREAL_HAVE_INT64_SUPPORT plays only “suggestive” role, it is undefined
>automatically for x64 builds on GCC to avoid clash among integer types.
>The better way would be to detect bit resolution of all integer types at compile time
>(using macros or meta-magic similar to boost) and add suitable routines to mpreal
>class. This could easily grow to be more complex than mpreal itself :) .
>Maybe I will come up with better solution in future versions, any suggestions are
>welcome.
So I think building in my constructor from the OP will fix things to work OK on a x64 system, but will need to be removed again if going back to x32 system otherwise it will cause a clash. The reason is that MPREAL_HAVE_INT64_SUPPORT macro gets defined on 32x and constructors for int64_t (aka long long int on 32x) get defined, so adding another such constructor will cause a clash; this is also the reason my code just worked out of the box on a 32 system. On a 64x system MPREAL_HAVE_INT64_SUPPORT macro is undefined and such constructors are removed since long int is already 64bit wide, so there was no need for the author to have a long long int constructor.
For sizes of various types check the C standard, long long has to be represented with at least 64 bits.
To see what the compiler really does with your code, you can use e.g. objdump -D on the binary (or the intermediate object file).
On 32 bit arch you will lose data if you cast from long long to long.
As far as I understand it, the compiler might have troubles deciding which constructor to use (basically can't decide whether to use ctor(int) or ctor(long int)).
EDIT:
#include <stdint.h>
...
uint64_t x = 5;
mpreal myVar(i);
works as the c-tor(uint64_t) is defined (or better said an unambiguous match can be found) - because on 64bit arch the (unsigned) long int is equivalent to uint64_t (for glibc it actually is defined as such). The error arises from the rules compiler uses when dealing with overloaded functions - for more information refer to the C++11 standard/draft.
Generally speaking, if you want your code portable, you should use the types defined in inttypes.h or stdint.h - which is C99 - i.e. uintXX_t and intXX_t. These types are guaranteed to provide the exact width, see the wiki link above for more info.

'long long int' is interpreted as 'long int'. How do I get round this?

I'm working on project involving c programming for my mathematics course at university.
I need to be able to handle large integers, larger than those that can be stored in a 'long int' datatype. So I tried using 'long long int', but if I try something like this:
long long int number;
number = 10000000000;
Then the error message says 'error: integer constant too large for "long" type'.
I've tried other datatypes like '___int64' and 'int_64t' I've tried including all the standard c libraries and I still get the same problem.
Strangely, when I try 'printf("LLONG_MAX = %lld\n", LLONG_MAX);', I get this:
LLONG_MAX = -1
I'm using Codeblocks 8.02 on windows xp, but I'm not sure what version of gcc compiler is installed since I'm using network computers on campus and I don't have permission to access the main filesystem. I don't want to have to bring my laptop into campus everyday. Please help! Thanks
When the compiler is compiling your C file and comes across an integer or floating point constant it needs to assign it a type. It will implicitly choose a default type for you. You can explicitly set the type by providing the compiler the integer suffix. An integer suffix can tell the compiler if it's a long,
long long, or unsigned type.
10 is implicitly a signed integer
10u, 10U is explicitly an unsigned integer
10l, 10L is explicitly a signed long integer
10ll, 10LL or 10i64 on win32 is explicitly a signed long long integer
10ull is explicitly an unsigned long long
Floating point types also have this situation. A type can either be a float, a double
or a long double. A floating point type usually defaults to double.
10.0 is implicitly a double
10.0f or 10.0F is explicitly a float
10.0l or 10.0L is explicitly a long double
Add an ll at the end of your integer constant.
In Microsoft environment use printf with this syntax :
__int64 i64 = 10000000000;
unsigned __int64 u64 = 10000000000000000000;
printf ( "%I64d\n", i64 );
printf ( "%I64u\n", u64 );
printf ( "%I64d\n", u64 ); <-- note this typo
Um, Code::Blocks uses GCC as its usual compiler. And recent versions of that support 64bit types explicitly.
So you should be able to
#include <inttypes.h>
uint64_t unsigned64BitNumber;
int64_t signed64BitNumber;
You should be able to use long long int with a gcc compiler but i think it may require using the c99 std code where as your default may be c89 mode. try adding --std=c99 to your compiler commandline and see if this helps :-)
Perhaps the compiler is confused by the int portion of the datatype - have you tried using a long long instead?
This website might help you out.
In addition to the previous comments about suffixes and gcc C99 mode, if you can't get long long to work, AND you only need integers up to 2^52, you can get away with using double. Integers up to 2^52 should be exactly representable as double assuming an IEEE double precision format (0 +1 bias exponent).
As people already posted, you should check what compiler you're using.
In Code:Blocks you do (in my version anyway, hopefully it will work for you too):
First find out what compiler is selected for your project by selecting
Project->Build options... and see what it says in the "Selected compiler"
Then select:
Settings->Compiler and debugger... and select the compiler you just found out.
Then click the "Toolchain executables" and see what it says for e.g. "C compiler".
Maybe if you succeed, and post your results, someone here will be able to help you.