long double vs long int - c++

I'm doing a program that calculates the probability of lotteries.
Specification is choose 5 numbers out of 47 and 1 out of 27
So I did the following:
#include <iostream>
long int choose(unsigned n, unsigned k);
long int factorial(unsigned n);
int main(){
using namespace std;
long int regularProb, megaProb;
regularProb = choose(47, 5);
megaProb = choose(27, 1);
cout << "The probability of the correct number is 1 out of " << (regularProb * megaProb) << endl;
return 0;
}
long int choose(unsigned n, unsigned k){
return factorial(n) / (factorial(k) * factorial(n-k));
}
long int factorial(unsigned n){
long int result = 1;
for (int i=2;i<=n;i++) result *= i;
return result;
}
However the program doesn't work. The program calculates for 30 seconds, then gives me Process 4 exited with code -1,073,741,676 I have to change all the long int to long double, but that loses precision. Is it because long int is too short for the big values? Though I thought long int nowadays are 64bit? My compiler is g++ win32 (64bit host).

Whether long is 64-bit or not depends on the model. Windows uses a 32-bit long. Use int64_t from <stdint.h> if you need to ensure it is 64-bit.
But even if long is 64-bit it is still too small to hold factorial(47).
47! == 2.58623242e+59
2^64 == 1.84467441e+19
although 47C5 is way smaller than that.
You should never use nCr == n!/(r! (n-r)!) directly do the calculation as it overflows easily. Instead, factor out the n!/(n-r)! to get:
47 * 46 * 45 * 44 * 43
C = ----------------------
47 5 5 * 4 * 3 * 2 * 1
this can be managed even by a 32-bit integer.
BTW, for #Coffee's question: a double only has 53-bits of precision, where 47! requires 154 bits. 47! and 42! represented in double would be
47! = (0b10100100110011011110001010000100011110111001100100100 << 145) ± (1 << 144)
42! = (0b11110000010101100000011101010010010001101100101001000 << 117) ± (1 << 116)
so 47! / (42! × 5!)'s possible range of value will be
0b101110110011111110011 = 1533939 53 bits
v
max = 0b101110110011111110011.000000000000000000000000000000001001111...
val = 0b101110110011111110010.111111111111111111111111111111111010100...
min = 0b101110110011111110010.111111111111111111111111111111101011010...
that's enough to get the exact value 47C5.

to use 64bit long, you should use long long. (as mentioned here)

KennyTM has it right, you're going to overflow no matter what type you use. You need to approach the problem more smartly and factor out lots of work. If you're ok with an approximate answer, then take a look at Stirling's approximation:
Ln(n!) ~ n Ln(n) - n
So if you have
n!/(k!*(n-k)!)
You could say that's
e(ln(n!/(k!*(n-k)!)))
which after some math (double check to make sure I got it right) is
e(n*ln(n)-k*ln(k)-(n-k)*ln(n-k))
And that shouldn't overflow (but it's an approximate answer)

It's easy to calculate binomial coefficients up to 47C5 and beyond without overflow, using standard unsigned long 32-bit arithmetic. See my response to this question: https://math.stackexchange.com/questions/34518/are-there-examples-where-mathematicians-needs-to-calculate-big-combinations/34530#comment-76389

Related

Multiply 2 large numbers in C++ have wrong result

There are 2 large integer numbers. When I multiply it the result is always wrong, even if I used long double and the result should be in valid range of long double:
long double f = 1000000000 * 99999;
I debugged, and the result is so strange: -723552768.00000000. Did I missed something? how can I multiple it?
Thanks and regard!
from the C++ standards:
4 An unsuffixed floating constant has type double. If suffixed by the
letter f or F, it has type float. If suffixed by the letter l or L, it
has type long double
auto fl = 1000000000.L * 99999.L;
std::cout << fl << "\n";
or
long double fl = 1000000000L * 99999.L;
std::cout <<"\n"<< fl << "\n";
Numeric literals are int by default in C++. Thus, the expression 1000000000 * 99999 is viewed as the multiplication of two int 's and therefore the result returned by the * operator is an int. This int is only converted to the long double variable f after the multiplication has taken place. Depending on your platform, the range of int is usually from -2147483648 to 2147483647 (or 4 bytes in size). However, the product of 1000000000 x 99999 is 9.9999 x 10^13 which falls outside this range and thus overflow occurs as the int variable is not large enough to hold the value.
To avoid this, at least one of the numbers the * operator operates on should be declared as a long double literal with the suffix .l or .L as follows:
long double f = 1000000000.L * 99999
In the above expression , the * operator will return a long double which is large enough to hold the resulting product before being assigned to f.
Agree with #feiXiang. You are basically multiplying two ints. To do correct calculations, you have to define large numbers as long double. See the code below:
#include <iostream>
using namespace std;
int main()
{
long double a = 1000000000;
long double b = 99999;
long double f = a * b;
cout<<f;
return 0;
}
Output:
9.9999e+13
Actually you invoke undefined behavior with:
long double f = 1000000000 * 99999;
First, evaluate 1000000000 * 99999, which is a multiplication of two int objects. Multiplying two int objects is always an int. Since int is not big enough to represent the result (most likely 32 bits), the upper bits are lost.
Since overflows in signed integer types is undefined, you just triggered undefined behavior. But in this case it is possible to explain what happened, even though it is UB.
The computation keeps only the lowest 32 bits, which should be (1000000000 * 99999) modulo (2**32) == 3571414528. But this value is too big for int. Since on PC int negatives are represented by two's complement, we have to subtract 2**32, every time 2**31<= result < 2**32. This gives -723552768
Now, the last step is:
long double f = -723552768
And that is what you see.
To overcome the issue, either use long long like this:
long double f = 1000000000LL * 99999;
Or double:
long double f = 1000000000.0 * 99999;
1000000000 and 99999 are integer numbers, then the result of 1000000000 * 99999 will be an integer before it is assigned to your variable, and the result is out of range of integer.
You should make sure that the result is a long double first:
long double f = (long double) 1000000000 * 99999;
Or
long double f = 1000000000LL * 99999;

why using int64_t gives wrong result while double works as expected for simple integer multiplications

here is my code :
using integer = int64_t;
integer factorial(integer number) {
return number <= 0 ? 1 : number * factorial(number - 1);
}
integer binomial_coefficent(integer n, integer r) {
return factorial(n) / (factorial(r) * factorial(n - r));
}
int main()
{
using namespace std;
cout << binomial_coefficent(40, 20) << endl;
return 0;
}
this prints
0
which is wrong answer but if i change integer type to double that will print 1.37847e+11
which is the correct answer,my question is why using int64_t gives me incorrect answer
and int64_t doesn't overflow either
It does though. For debugging things like this, you can run this with -fsanitize=signed-integer-overflow (implied by -fsanitize=undefined) in GCC or clang to see:
runtime error: signed integer overflow: 21 * 2432902008176640000 cannot be represented in type 'long'
runtime error: signed integer overflow: 2432902008176640000 * 2432902008176640000 cannot be represented in type 'long'
40! is about 8e47. A 64 bit signed integer could hold at max 2^63-1, about 1e19.
factorial(40) does overflow, and since overflow of signed integer types is undefined behavior, anything you observe could not be explained.
Welcome in the world of finite precision numbers! fact(40) is 815915283247897734345611269596115894272000000000 or 0x8eeae81b84c7f27e080fde64ff05254000000000 which will obviously not fit even in a uint64_t neither in a 128 bits long long since it actually requires 160 bits!
But the binomial coefficient 40, 20 can indeed be computed using uint64_t provided you use the correct algorithm that human beings were used to before computers come everywhere around:
integer binomial_coefficient(integer n, integer r) {
integer bc = 1;
integer q = n - r;
for(integer i=1; i<=r; i++) {
br = br * (q + i) / i;
}
return bc;
}
This one will give you the correct value of 137846528820 with no overflow.
(above function omits the test for r <= n/2 that can be an additional optimisation because Cn,p is by construction Cn,n-p)

Trying to avoid rounding in double point arithmetic, unable to as double is exceeded

I am trying to solve Project Euler 94 first with brute force.
This requires me to work out whether an area of a given triangle is integral.
I do know the base and height, which are both integral.
long double area = 0.5*h*b;
When using double point arithmetic I arrive at answers which exceeds the exponent and sacrifices the precision of the fraction.
Is there any way for me to to ignore most significant part of the exponent and solely focus on fraction as I am only interested in whether the area is integral and not what size it is. Also I am using Visual Studio which I believe does not have long double just double?
EDIT
This is my code now. It reduced number of wrong triangles picked up by 3 from 26 to 23.
EDIT 2
I have read everyone's suggestions, but I am still not able to filter out the heights which are not integral my latest code looks like this. I know I am doing something really stupid but just can't pin point it.
void findAET(){
int gt = 0; //triangle count is
for(long long ss = 3; ss<333333334;ss+=2){ //skips out odd bases
for(int c = -1; c<2; c+=2){
long long base = c + ss;
if((sqrt((ss*ss)-(double)((base/2)*(base/2)))) == int(sqrt(((ss*ss))-(double)((base/2)*(base/2)))) ){ // check if height is an integer
if( (int)((sqrt((ss*ss)-(double)((base/2)*(base/2))))*base)%2==0){
cout<<" same sides "<<ss<<" base "<< base <<endl;
gt++;
}
}
}
}
}
}
As was mentioned in the comments, if bothh and b are both integer types, then 0.5*h*b has an integer result if either h or b are even:
if (((h % 2) == 0) || ((b % 2) == 0)) {
printf("area is integral\n");
} else {
printf("area is not integral\n");
}
If (b * h) % 2 == 0 then we know that (b * h) / 2 will be an integer result. Then all you need is a integer data type. I am not sure how big of a number you need to compute but a long long can hold up to 9223372036854775807 at 64 bits.
// Returns zero if height is not an integer
// Returns exact height if there is an exact height
// Relies on unsigned having at least 30 bits and long long at least 61
unsigned find_height( unsigned x, unsigned y){
if ( y & 1 ) return 0; // Height is not an integer because height squared is not
long long hs = (long long)x*x - (long long)y*y/4;
unsigned result = sqrt(hs) + .5;
if ( (long long)result*result != hs ) return 0;
return result;
}
If you compute height this way, you don't need any integer tests for area. Area will be an integer whenever height is an integer.
With a 60 bit integer input, sqrt(double) is accurate enough that the closest integer will be the correct integer when the true answer is an integer. But since a 60 bit integer can't really be held in a double, the test of whether the result of sqrt(double) is an integer can be incorrect in either direction from whether the true answer is an integer. But it is trivial to find out whether the closest integer (unsigned)(D+.5) is the true answer, by just squaring it and comparing.

How to Calculate 2^x mod n = 1 in less than 1 second

I want to write the program that Calculate 2^x mod n = 1 we have n is an integer but, we should calculate x.I wrote the code but my code work too slow in big n.Can you suggest me a good way that work less than 1 second to solve this problem.
here is my code:
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
long long int n,cntr=1,cheak;
cin >> n;
while (1)
{
if (n % 2 == 0)
{
break;
}
cheak=pow(2, cntr);
if (cheak % n == 1)
break;
cntr++;
}
cout << cntr << endl;
}
Some suggested modifications to your current approach: Note: a better approach follows!
Change your long long int to unsigned long long int. This will give you one more bit.
Change while (1) to while (cntr < 64). The size of unsigned long long is likely only 64 bits. (It's guaranteed to be at least 64 bits, but not larger than that.) You would then need to check whether your loop succeeded, however.
Change cheak to calculate 2n as 1ull << cntr. Make sure to include the ull suffix, which says this is an unsigned long long.
The << operator shifts bits to the left. Shifting all the bits to the left by 1 doubles the integer value of the number, assuming no bits "shifted away" off the left of the value. So, 1 << n will compute 2n.
The suffix ull indicates an integer constant is an unsigned long long. If you omit this suffix, 1 will be treated as an integer, and shift values above 31 will not do what you want.
However, all of the above are merely refinements on your current approach. It's worth understanding those refinements to better understand the language. They don't, however, look at the bigger picture.
Modular multiplication allows you to find (A * B) mod C as ( (A mod C) * (B mod C) ) mod C. How does that help us here?
We can rewrite the entire algorithm in a way that only limits N and X to the precision of the machine integers, and not 2N:
int main()
{
unsigned int modulus;
unsigned int raised = 2;
int power = 1;
std::cin >> modulus;
if (modulus % 2 == 1)
{
while (raised % modulus != 1)
{
raised = ((unsigned long long)raised * 2) % modulus;
power++;
}
std::cout << power << std::endl;
} else
{
std::cout << "modulus must be odd" << std::endl;
}
}
The cast to unsigned long long above allows modulus to be as large as 232 - 1, assuming unsigned int is 32 bits, without the computation overflowing.
With this approach, I was able to very quickly find answers even for very large inputs. For example, 111111111 returns 667332. I verified 2677332 mod 111111111 == 1 using the arbitrary precision calculator bc.
It's very fast. It computed 22323860 mod 4294967293 == 1 in less than 0.07 seconds on my computer.
Epilog: This highlights an important principle in programming: Really, this was a math problem more than a programming problem. Finding an efficient solution required knowing more about the problem domain than it did knowing about C++. The actual C++ code was trivial once we identified the correct mathematical approach.
It often goes this way, whether it's the mathematics or some other algorithmic aspect. And, it shouldn't surprise you to learn that discrete mathematics is where many of our graph and set algorithms come from. The programming language itself is a small piece of the big picture.
For each k between 1 and ceil(sqrt(n)), compute 2^k mod n and 2^(k ceil(sqrt(n))) mod n. Then compute the modular inverse of each 2^k. Sort all of the inverse(2^k)s into an array foo and the 2^(k ceil(sqrt(n))s into an array bar. There will be at least one value in common between the two arrays; find it. Say inverse(2^a) = 2^(b ceil(sqrt(n))). Then 2^(a + b ceil(sqrt(n))) = 1 (mod n).
How's your professor's sense of humor?
#include <iostream>
int main() { std::cout << 0 << '\n'; }
always prints a correct answer to the problem as stated.
pow is quite expensive in calculations, but if you have 2 as its first argument, you can better do a shift left, as shift left is equal to multiplying by 2:
cheak = (1 << cntr);

Method to find 2^x quickly

How to find 2^x quickly in C. If you guys have any idea please help.
Is it int or float? For int, use left shift. For float, pow() function
Bitshift to the left, this multiplies numbers by 2 for every place shift, in the same way that shifting decimal numbers to the left multiplies them by 10.
Use the << operator, like so:
int twoPowZero = 1; // any number^0 is 1
int twoPowOne = 1 << 1; // this sets the '2' bit to '1'
int twoPowTwo = 1 << 2;
int twoPowFive = 1 << 5;
int twoPowTen = 1 << 10;
and so on until you get to 1 << 30. If you're using a signed 32-bit integer then 1 << 31 will give you -2147483648 because of two's complement. If you want to go higher than use long long unsigned int or uint64_t (64-bit integer). Or if your platform supports it: uint128_t.
If you want to go even higher, you'll need to roll your own "big integer" code. Note that some platforms and compilers come with a 128-bit integer type, but runtime performance varies: they may require a processor that can perform 128-bit operations, or they might break it down into two 64-bit operations.
Recall that in a binary system a bit in a position N represents 2^N. Therefore, the formula for positive int is
1 << x
#include <stdio.h>
#include <math.h>
int main ()
{
printf ("7.0 ^ 3 = %lf\n", pow (7.0,3));
printf ("4.73 ^ 12 = %lf\n", pow (4.73,12));
printf ("32.01 ^ 1.54 = %lf\n", pow (32.01,1.54));
return 0;
}
output:
7.0 ^ 3 = 343.000000
4.73 ^ 12 = 125410439.217423
32.01 ^ 1.54 = 208.036691
#include <math.h>
float powf(float x, float y); /* C99 */
double pow(double x, double y);
long double powl(long double x, long double y); /* C99 */
Set a 1 in the xth bit position: 1 << x.
In this case x should be less than the width of integer type, and x should be positive.