In some part of my program, I have an array which contains float numbers (for example 9.8, 5.0, 4.45). What I have to do is take those numbers to another array and if they are float (I mean if they have digits after the decimal point that are not zero), then multiply them by 10 enough times to make it an int value (so from the first example, after that I should have 98, 5, 445). I know it doesn't sound clear but it's hard for me to describe my problem better.
My attempt was to do this but I have errors.
for(i=0;i<size;i++)
{
if(teb[i]%10!=0)
{
while(teb[i]%1!=0)
{
teb[i]=teb[i]*10;
}
}
}
I have error: invalid operator to binary % (have float and int) and I am not sure if I can use char or similar variables.
In my opinion, you'll not be able to manage this sanely without using string formatting and then converting from string back to floating-point. I use double rather than float. This is the code I came up with, including your three test values as the first three.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static inline int all_same_as(char *str, char c)
{
while (*str != '\0')
{
if (*str++ != c)
return 0;
}
return 1;
}
static inline void zap_trailing(char *str, char c)
{
char *end = str + strlen(str);
while (end > str)
{
if (*(end - 1) != c)
return;
*--end = '\0';
}
}
static inline void zap_leading(char *str, char c)
{
char *end = str;
while (*end == c)
end++;
if (end > str)
memmove(str, end, strlen(end) + 1); /* Not memcpy()! */
}
int main(void)
{
double d[] =
{
9.8,
5.0,
4.45,
1.0,
18.0,
9.25,
8.719,
2.78128,
2721.0/1001.0,
3.14159,
355.0/113.0,
0.001234, /* Smaller */
1.2345E+13, /* Biggest */
1.2345E-13, /* Smallest */
};
enum { NUM_D = sizeof(d) / sizeof(d[0]) };
for (int i = 0; i < NUM_D; i++)
{
char buffer1[32];
snprintf(buffer1, sizeof(buffer1), "%.6f", d[i]);
char buffer2[32];
strcpy(buffer2, buffer1);
zap_leading(buffer2, ' '); /* Not needed with %.6f; was needed with %10.6f */
char *dot = strchr(buffer2, '.');
if (all_same_as(dot + 1, '0'))
*dot = '\0';
else
{
zap_trailing(dot + 1, '0');
size_t len = strlen(dot + 1);
memmove(dot, dot + 1, len + 1); /* Not memcpy()! */
}
double iv = strtod(buffer2, NULL);
printf("%8g = %8.2g = %8.3g = %10s (converted: %10s - [%s] %g)\n",
d[i], d[i], d[i], buffer1, buffer2, buffer2, iv);
}
return 0;
}
Output:
9.8 = 9.8 = 9.8 = 9.800000 (converted: 98 - [98] 98)
5 = 5 = 5 = 5.000000 (converted: 5 - [5] 5)
4.45 = 4.5 = 4.45 = 4.450000 (converted: 445 - [445] 445)
1 = 1 = 1 = 1.000000 (converted: 1 - [1] 1)
18 = 18 = 18 = 18.000000 (converted: 18 - [18] 18)
9.25 = 9.2 = 9.25 = 9.250000 (converted: 925 - [925] 925)
8.719 = 8.7 = 8.72 = 8.719000 (converted: 8719 - [8719] 8719)
2.78128 = 2.8 = 2.78 = 2.781280 (converted: 278128 - [278128] 278128)
2.71828 = 2.7 = 2.72 = 2.718282 (converted: 2718282 - [2718282] 2.71828e+06)
3.14159 = 3.1 = 3.14 = 3.141590 (converted: 314159 - [314159] 314159)
3.14159 = 3.1 = 3.14 = 3.141593 (converted: 3141593 - [3141593] 3.14159e+06)
0.001234 = 0.0012 = 0.00123 = 0.001234 (converted: 0001234 - [0001234] 1234)
1.2345e+13 = 1.2e+13 = 1.23e+13 = 12345000000000.000000 (converted: 12345000000000 - [12345000000000] 1.2345e+13)
1.2345e-13 = 1.2e-13 = 1.23e-13 = 0.000000 (converted: 0 - [0] 0)
You can make choices about how many decimal digits to support, etc. I chose to use up to 6 after the decimal point (format %.6f used with snprintf()). I included very small (1.23E-13) and very large (1.23E+13) values; the behaviour for even bigger or smaller values is similar.
I initially used %10.6f in the snprintf() statement. When I did that, values were printed with leading blanks. The zap_leading() function removes those. The code has since been revised to use %.6f and there are no leading blanks to zap. I left the code to zap leading characters in place; it could be removed too.
Most decimal fractions expressed as some finite number of digits in base 10 cannot be stored exactly in the binary floating point representations typically used in most implementations.
If you know the numbers are only supposed to be accurate to a fixed number of decimal places n, you can first multiply by 10n and round to the nearest integer. Then strip off up to n trailing zero digits.
For example, for up to 3 decimal places:
for(i=0;i<size;i++)
{
long x = round(teb[i] * 1000.0);
for (int j = 0; j < 3; j++)
{
if (x % 10 == 0)
{
x /= 10;
}
else
{
break;
}
}
teb[i] = x;
}
Normally I don't provide answers to homework problems, but since this is such a bad problem, I'm making an exception.
Before I proceed, let me say that the original problem is meaningless and impossible. Since it's impossible, there's no good way to solve it. So the program I'm going to present has a number of problems, some quite serious.
The core of the program does what the problem asks: As long as the fractional part of one of the numbers is not 0, it multiplies the number by 10. Computing "the fractional part of the number" is performed by an auxiliary function I've written, fractionalpart(). First we'll look at the program, then I'll explain its remaining problems.
#include <stdio.h>
float in[] = {9.8, 5.0, 4.45};
int out[3];
float fractionalpart(float f)
{
return f - (int)f;
}
int main()
{
int i;
for(i = 0; i < 3; i++) {
float tmp = in[i];
while(fractionalpart(tmp) > 0.001) {
tmp = tmp * 10;
}
out[i] = tmp;
}
printf("out:\n");
for(i = 0; i < 3; i++) printf("%d\n", out[i]);
}
The problems this has relate to the fact that, on an ordinary computer using ordinary floating-point representations, there is no such number as 9.8. There's no such number as 4.45, either. What you thought was the float number 4.45, for example, is represented internally as something like 4.44999980926513671875. So a "proper" version of this program would multiply it by 10 a total of twenty times, converting it to 444999980926513671875. But that number won't even fit in a 64-bit integer!
So this program cheats: it doesn't loop until the fractional part is exactly 0; it instead loops until the fractional part is less than 0.001. Where did that number come from? The answer is: nowhere, I pulled it out of the air, it seemed like a good guess. You can experiment with bigger or smaller fudge factors if you like.
The bigger problem -- and you've probably thought of this already -- is that the program assumes that the "fractional part" actually does go down to something like 0.001 or 0.0001. But that's not necessarily true! As we just saw, the number 4.45 is "really" 4.44999980926513671875 inside, so after multiplying by 10 twice, it looks like the program is going to have an integer value of 444 (not 445), and the fractional part is going to be 0.999980926513671875, which is not less than 0.001, so the program is going to keep going!
Actually, it doesn't keep going, it does get the "right answer", at least on my machine (and I think I know why), but there are probably plenty of numbers (roughly half of them, actually) where there will be an intermediate result more like 0.999 than 0.001, and this program will do the wrong thing.
I hate posting code with serious problems like this, it's very tempting to try to write an "improved" version, but it would be much messier, and really, the original question is such a horrible one that it just isn't worth it. (It would be instructive to figure out and explain why this program does seems to work, at least most of the time -- why it doesn't get confused by the occasional 0.999 value -- but I don't have time for that just now, either.)
Related
We were assigned a task to convert octal numbers to binary and decimal. Smaller numbers works just fine but it then gives a different output at a higher input. Here is the code:
#include <stdio.h>
void main() {
unsigned long n, g, ans = 1, r = 0, dec = 0, place = 1, bin = 0;
printf("Conversion: Octal to decimal and binary.\n");
printf("Enter number: ");
scanf("%lu", &n);
printf("%lu is ", n);
for (g = n; g != 0; ans = ans * 8) {
r = g % 10;
dec = dec + r * ans;
g = g / 10;
}
printf("%lu in Decimal Form. \n", dec);
printf("%lu is ", n);
for (; dec != 0; place = place * 10) {
r = dec % 2;
bin = bin + (r * place);
dec = dec / 2;
}
printf("%lu in Binary Form.\n", bin);
}
We were only required to use limited data types and control structures. No arrays, strings, functions or such.
The input in our teacher's test case is 575360400 which must print an output of 101111101011110000100000000 in binary and 100000000 in decimal. But the output in binary is 14184298036271661312. I used unsigned long already and it just won't work.
I don't know how this is possible with the given restrictions and your comments and answers will be really much of a help.
Smaller numbers works just fine but it then gives a different output at a higher input.
Overflow
Input "575360400" (base 8) converts to a 27-bit value. For place = place * 10 ... bin = bin + (r * place); to work, bin needs to be a 90-bit unsigned long. unsigned long is certainly 64-bit or less.
OP needs a new approach.
I'd start with reading the octal input with scanf("%lo", &n); and printing the decimal with printf("%lu\n", n);.
To print in binary, without arrays, functions, etc., consider a mask, first with the most significant bit, that is shifted right each iteration.
bool significant_digit = false;
// Form 0b1000...0000
// 0b1111... - 0b01111..
unsigned long mask = ULONG_MAX - ULONG_MAX/2;
while (mask) {
bool bit = mask & n;
if (bit || significant_digit || mask == 1) {
significant_digit = true;
printf("%d", bit);
}
mask >>= 1;
}
printf("\n", bit);
}
Better approaches exist. Yet with OP's artificial limitations: "No arrays, strings, functions or such.", I opted for something illustrative and simple.
Or wait until 2023
C2x expected to support printf("%lb\n", n);. Just ask the professor for an extension 😉.
My code is taking a string format and compose it into a buffer (without sprintf, itoa etc).
I'm having trouble converting a float number to string, as I need to have precision of at most 7 digits with no trailing zeros. as well as convert each number in the float variable to char (but in that matter I don't need any help).
I tried several methods, all including math calculations, but nothing has brought me to the desired outcome.
Here's my code so far, but it is messy and also sometimes gives incorrect outcome. I also believe there is a more clean and less-complicated way to do it.
any help will be widely appreciated.
if (*format == 'f') {
float f = *(float*)ptrs[counter];
char str[30];
int b, c, m, k = 7, i = 0, l = 0;
int a = f;
f -= a;
while (k >= 0) {
l = pow(10, k);
m = a / l;
if (m > 0) {
break;
}
k--;
}
printf("%d", k);
for (l = k + 1; l > 0; l--) {
b = pow(10, l - 1);
c = a / b;
str[i++] = c + 48;
a %= b;
}
str[i++] = '.';
for (l = 0; l < 7; l++) {
f *= 10.0;
b = f;
str[i++] = b + 48;
f -= b;
}
for (i = 0; i < 7; i++) {
*buffer = str[i];
buffer++;
}
counter++;
str[i] = '\0';
for example:
input: float v2 =0.9372;
output: .937199
desired output: 0.9372
input: float v2 =0.25000;
output: 1.25000
desired output: 0.25
he's messy and also sometimes gives incorrect outcome
At some point given the base 2 nature of typical floating point, the programmer needs to make choices:
Short code that gets close to the correct answer.
Exact correct conversion with a fair amount of code. e.g. Function to print a double - exactly
Something in between.
With common floating point encoding, there are also issues of
Infinity
Not-a-number.
Oddities like -0.0
And how portable to make the code?
Sources of inexactness
OP's use of int limits float to about [INT_MIN...INT_MAX]. Code fails for float much outside that range. Could use long long to get some more range without a great deal of code change. Better yet research float modff(float value, float *iptr).
float f = ...;
// int a=f;
long long a=f;
Repeated use of f*=10.0 below with a fractional value in f injects a possible rounding (inexactness), at each iteration.
for(l=0;l<7;l++) {
f*=10.0;
Code makes no effort to round given that f may not be 0.0 after the fraction forming for(l=0;l<7;l++) { f*=10.0; loop. I see this as a place to improve precision. This area is also tricky as the round-up may effect many leading digits when they are 9, eventually needing a shift of the string buffer. In the 0.93721, after this loop, f was about 0.74. Since more than 0.5, a rounding would have given the answer of ".9371999" --> ".9372000".
Code aims for 7 decimal digits after the .. Values, as a decimal in code, assigned to a float match to 6 to 9 significant decimal places - which includes digits to the left of .. Expectations should not get too high.
Improvement idea
When the number of fraction digits desired is small, perform 1 scaling/round
// ASSUME f >= 0.0, (sign handling done before here)
long long a=f;
f-=a;
int int_f = round(f*pow(10, 7));
if (int_f < 10000000) {
later_printf_the_7_digits(int_f);
} else {
a++;
later_printf_the_7_digits(0);
}
I would like to produce a function which takes an integer x and char array in, and returns a string x steps into the sequence.
For example, consider the alphabet 'abc', which would produce the strings a, b, c, aa, ab, ac, ba, bb, bc, ca, cb, cc, aaa, aab... If the index 0 was passed in, I would expect the output to be 'a'; likewise, if the index 34 was passed in, I would expect the output 'cbb'.
For the alphabet '0123456789' I would expect the strings 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11...
I have written the following thus far, but am getting stuck on cases 21-23, 33-35, 45-47 where the behaviour deviates and I've been staring at this for a number of hours now without a pattern jumping out at me (with respect to the alphabet size and index). At first I didn't notice the issue, using a larger sized alphabet until it created bigger issues further in my program.
I'm not going to pretend the code below is in anyway elegant, following good practice, nor optimised - at this stage I really just want to understand the correct implementation of this pattern and have been changing things all over the place to attempt to resolve the issue. Apologies in advance if the variable names are confusing. Also, is this a common pattern/issue? I have tried to search for similar algorithms but have been unable to find anything with the terms that come to mind.
unsigned long power(int num, int exp)
{
int i;
unsigned long ret = num;
if (exp == 0) return 1;
for (i = 1; i < exp; i++)
{
ret *= num;
}
return ret;
}
unsigned long sumsqr(int base, int exp)
{
unsigned long sum;
for (sum = 0; exp > 0; exp--)
{
sum += power(base, exp);
}
return sum;
}
char * generateStringT(unsigned long index, char * charmap)
{
unsigned long scaler;
unsigned long remainder;
unsigned long divisor;
int base;
int exponent;
int factor;
char * buffer;
char * string;
int i;
buffer = malloc(sizeof(char) * 100);
i = 0;
base = strlen(charmap);
exponent = 0;
divisor = 0;
remainder = index;
while(sumsqr(base, exponent) <= index)
{
exponent++;
}
exponent--;
factor = exponent;
while(factor >= 0)
{
divisor = power(base, factor);
if ((factor > 1) && (exponent > 0))
divisor += power(base, factor-1);
scaler = remainder/divisor;
remainder = remainder - scaler * divisor;
printf("%lu,", scaler);
if ((factor == exponent) && (exponent > 0)) scaler--;
buffer[i++] = charmap[scaler];
factor--;
}
buffer[i++] = '\0';
string = malloc((strlen(buffer) + 1) * sizeof(char));
strcpy(string, buffer);
free(buffer);
return string;
}
What you are trying to do there looks like a base conversion, but actually is slightly different. Any number in any base can be thought as if they have infinitely many preceding zeros (or whatever the least significant digit is at that base) behind the represented number. This is not true in your case.
In your case, you lay importance to the amount of digits on the number you represent, making it slightly more complicated to index them. With bases in maths, it is easy to calculate the index of a represented number in any base b; that is, sum of the rank times the base raised to the power of order for each digit. In your case, the index builds up an additional sum_{k = 1}^{amount.of.digits.on.our.number - 1} base^k. If we subtract that addition from the index, our task becomes rather easy.
That addition can be calculated using your sumsqr function.
Here, I have changed your code just a little, with comments at where I've done changes, which is able to resolve many, just like you expect it to:
// added this
remainder -= sumsqr(base, exponent);
while (factor >= 0)
{
divisor = power(base, factor);
// commented this out
// if ((factor > 1) && (exponent > 0))
// divisor += power(base, factor - 1);
scaler = remainder/divisor;
remainder = remainder - scaler * divisor;
printf("%lu,", scaler);
// commented this out
// if ((factor == exponent) && (exponent > 0))
// scaler--;
buffer[i++] = charmap[scaler];
factor--;
}
I am not exactly sure what you were trying to do with the parts I've commented out. My guess is that you were trying to increase the divisor by that amount of difference I've talked previously, instead of decreasing the index or remainder by that amount.
Hope this helps in any way.
Not a fix (at a glance, your code uses a similar idea -- but more complicated!), but this is the code I used to convert an integer index to an a,b,c-format page number:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *number_alpha (char *dest, int value, char *base)
{
char *ddest = dest, *startdest = dest, swop;
if (value < 0)
{
value = -value;
*dest = '-';
startdest++;
ddest++;
}
value++;
do
{
*ddest = base[((value-1) % strlen(base))];
ddest++;
value = (value-1)/strlen(base);
} while (value > 0);
*ddest = 0;
ddest--;
while (ddest > startdest)
{
swop = *ddest;
*ddest = *startdest;
*startdest = swop;
startdest++;
ddest--;
}
return dest;
}
int main (int argc, char **argv)
{
int number;
char result[256];
if (argc != 3)
{
printf ("usage: [number] [string]\n");
return -1;
}
number = strtol (argv[1], NULL, 10);
number_alpha (result, number, argv[2]);
printf ("%d in 'base' %s yields %s\n", number, argv[2], result);
return 0;
}
It is very similar to the common task 'convert an integer to decimal notation'. By removing the value++ and changing (value-1) twice to just value in number_alpha, you get a bog-standard Int-To-Ascii routine. This one is special because the "wrap" occurs at a different place: for a base of 0123456789, incrementing 9 shows 00, not 10.
Sample outputs:
0 in 'base' abc yields a
34 in 'base' abc yields cbb
34 in 'base' 0123456789 yields 24
-34 in 'base' abc yields -cbb
9 in 'base' 0123456789 yields 9
10 in 'base' 0123456789 yields 00
--
See Translate a column index into an Excel Column Name for a couple of implementations in other languages. They seem to focus on recursive solutions, where mine is linear (for better or worse).
I have written a program in C to convert a floating point number represented in binary (1101.11) into a decimal (13.75).
However, I cannot seem to get the correct value out of the algorithm.
What is the correct method for converting a binary floating point number into a decimal?
I am using Dev CPP compiler (32 bit). The algorithm is defined below:
void b2d(double p, double q )
{
double rem, dec=0, main, f, i, t=0;
/* integer part operation */
while ( p >= 1 )
{
rem = (int)fmod(p, 10);
p = (int)(p / 10);
dec = dec + rem * pow(2, t);
t++;
}
/* fractional part operation */
t = 1; //assigning '1' to use 't' in new operation
while( q > 0 )
{
main = q * 10;
q = modf(main, &i); //extration of frational part(q) and integer part(i)
dec = dec+i*pow(2, -t);
t++;
}
printf("\nthe decimal value=%lf\n",dec); //prints the final output
}
int main()
{
double bin, a, f;
printf("Enter binary number to convert:\n");
scanf("%lf",&bin);
/* separation of integer part and decimal part */
a = (int)bin;
f = bin - a;
b2d(a, f); // function calling for conversion
getch();
return 0;
}
You are not, as you believe, reading "1101.11" as a floating point number represented in binary. You are reading it as a base-10 floating point number converted into an IEEE double-precision floating-point value, and then trying to change the base.
The inherent imprecision of this intermediate step is the reason for your problem.
A better approach, as suggested by Vicky, is to:
read "1101.11" as a string or line of text
convert the whole and fractional parts (whole=b1101=13 and numerator=b11=3, denominator=4)
re-combine these into whole + numerator/denominator = 13.75
Solution
The following will work as expected:
Output:
➤ gcc bin2dec.c -lm -o bin2dec && bin2dec
1101.11 -> 13.750000
1101 -> 13.000000
1101. -> 13.000000
.11 -> 0.750000
Code (bin2dec.c):
#include <stdio.h>
#include <math.h>
double convert(const char binary[]){
int bi,i;
int len = 0;
int dot = -1;
double result = 0;
for(bi = 0; binary[bi] != '\0'; bi++){
if(binary[bi] == '.'){
dot = bi;
}
len++;
}
if(dot == -1)
dot=len;
for(i = dot; i >= 0 ; i--){
if (binary[i] == '1'){
result += (double) pow(2,(dot-i-1));
}
}
for(i=dot; binary[i] != '\0'; i++){
if (binary[i] == '1'){
result += 1.0/(double) pow(2.0,(double)(i-dot));
}
}
return result;
}
int main()
{
char bin[] = "1101.11";
char bin1[] = "1101";
char bin2[] = "1101.";
char bin3[] = ".11";
printf("%s -> %f\n",bin, convert(bin));
printf("%s -> %f\n",bin1, convert(bin1));
printf("%s -> %f\n",bin2, convert(bin2));
printf("%s -> %f\n",bin3, convert(bin3));
return 0;
}
Explanation
The above code works by first finding the index of the decimal point in the number.
Once that is known, it walks the string both backwards and forwards from this index, adding the appropriate value to the result variable.
The first loop walks backwards from the decimal point and accumulates the powers of 2 if the character is 1. It takes the distance from the decimal point as the power of two, minus one for the indexing to be correct. Ie, it accumulates :
pow(2,<distance-from-decimal-point>)
The loop stops when the index reaches the beginning of the string.
The second loop walks forward until the end of the string, and deals with the fractional part as expected it also uses the distance from the index, but this time accumulates fractional parts:
1/pow(2,<distance-from-decimal-point>)
Worked out example:
1101.11 = 1101 + 0.11
1101 = 1*2^3 + 1*2^2 + 0*2^1 + 1*2^0 = 8 + 4 + 0 + 1 = 13
0.11 = 1/(2^1) + 1/(2^2) = 0.5 + 0.25 = 0.75
1101.11 = 13.75
Beware of malformed input. "10gsh.9701072.67812" will give you a result. It won't mean much :)
This piece of code behaves abnormally: I added some simple print statement
while(q>0)
{
double i;
main=q*10.0;
q=modf(main, &i); //extration of frational part(q) and integer part(i)
cout << "main = " << main << " frac part " << q << " int part " << i << endl;
cin.get();
dec=dec+i*pow(2,-t);
t++;
}
When you input 1101.11, the following output shown:
Enter binary number to convert(e.g: 1101.11 which will be 13.75 in decimal):
1101.11
bin in main 1101.11
p 1101 q 0.11
//inside the above while loop code
main = 1.1 frac part 0.1 int part 1
main = 1 frac part 1 int part 0 //^^^^^Error, given main=1, it should output integer part 1, fraction part 0
main = 10 frac part 1 int part 9 //^^^^^same strange error here, it should exit while already
So you got wrong result. I tested modf separately with input 1, it gave correct result.
So my guess is that you are reading the binary number as double, then tries to convert this double to binary back. There might be something going on under the hood for the precision of number though it shows that it is 1101.11. As suggested by #Useless, You may need to read the number as a string, figure out the substring before and after the decimal point . Then convert this two part into decimal separately.
In my C code, I want to calculate the factorial for numbers in the range 1 to 100. For small numbers, the function works, but for bigger numbers (for example 100!) it returns incorrect result. Is there any way to handle factorial of large numbers in C?
The compiler I'm using is gcc v4.3.3.
My code is as follows:
#include <stdio.h>
#include <math.h>
double print_solution(int);
int main(void)
{
int no_of_inputs, n;
int ctr = 1;
scanf("%d",&no_of_inputs); //Read no of inputs
do
{
scanf("%d",&n); //Read the input
printf("%.0f\n", print_solution(n));
ctr++;
} while(ctr <= no_of_inputs);
return 0;
}
double print_solution(int n)
{
if(n == 0 || n == 1)
return 1;
else
return n*print_solution(n-1);
}
No standard C data type will accurately handle numbers as large as 100!. Your only option if to use arbitrary precision integer arithmetic, either through a library or done by yourself.
If this is just some hobby project, I'd suggest trying it yourself. It's kind of a fun exercise. If this is work-related, use a pre-existing library.
The largest C data type you'll normally get is a 64-bit integer. 100! is in the order of 10157, which takes at least 525 bits to store accurately as an integer.
100 factorial is huge, to be precise it's 93326215443944152681699238856266700490715968264381621468592963895217
59999322991560894146397615651828625369792082722375825118521091686400
00000000000000000000.
Maybe you should use a bignum library like GMP. It's got nice docs, a pretty consistent interface, speed and if you're on Linux your distro probably has a package (I think mine installs it by default)
To approximately compute factorials of large numbers you can go this way:
n! = n * (n-1)!
so log(n!) = log(n) + log(n-1!)
Now you can use dynamic programming to compute log(n!) and calculate
n! as (base)^(log-value)
If you don't want to use a bigint library, the best you can do with the stdlib is using long double and tgammal() from math.h:
long double fact(unsigned n)
{
return tgammal(n + 1);
}
This'll get you 100! with a precision of 18 decimals on x86 (ie 80 bit long double).
An exact implementation isn't that complicated either:
#include <math.h>
#include <stdio.h>
#include <string.h>
void multd(char * s, size_t len, unsigned n)
{
unsigned values[len];
memset(values, 0, sizeof(unsigned) * len);
for(size_t i = len; i--; )
{
unsigned x = values[i] + (s[i] - '0') * n;
s[i] = '0' + x % 10;
if(i) values[i - 1] += x / 10;
}
}
void factd(char * s, size_t len, unsigned n)
{
memset(s, '0', len - 1);
s[len - 1] = '1';
for(; n > 1; --n) multd(s, len, n);
}
int main(void)
{
unsigned n = 100;
size_t len = ceill(log10l(tgammal(n + 1)));
char dstr[len + 1];
dstr[len] = 0;
factd(dstr, len, n);
puts(dstr);
}
Everyone is telling you the correct answer however a couple of further points.
Your initial idea to use a double to get a wider range is not working because a double can not store this data precisely. It can do the calculations but with a lot of rounding. This is why bigint libraries exist.
I know this is probably an example from a tutorial or examples site but doing unbounded recursion will bite you at some point. You have a recursive solution for what is essentially an iterative process. You will understand why this site is named as it is when you try running your program with larger values (Try 10000).
A simple iterative approach is as follows
int answer, idx;
for (answer = 1, idx = 1; idx <= no_of_inputs; idx++ ) {
answer = answer * idx;
}
printf("Factorial of %3d = %d\n", no_of_inputs, answer);
this is what i made to solve a google riddle some years ago, it uses GMP library http://gmplib.org/:
#include <stdio.h>
#include "gmp.h"
void fact(mpz_t r,int n){
unsigned int i;
mpz_t temp;
mpz_init(temp);
mpz_set_ui(r,1);
for(i=1;i<=n;i++){
mpz_set_ui(temp,i);
mpz_mul(r,r,temp);
}
mpz_clear(temp);
}
int main(void) {
mpz_t r;
mpz_init(r);
fact(r,188315);
/* fact(r,100); */
gmp_printf("%Zd\n",r);
mpz_clear(r);
return(0);
}
gcc -lgmp -o fact fact.c
./fact
you could try going for "unsigned long long" type, but thats the maximum you can get with built in types.
I'd suggest (as cletus has already mentioned) either going with a known implementation of big numbers, or writing one yourself. "its a nice exercise" x 2.
If you want to use only the standard data types and you do not need the exact answer, then compute the logarithm of n! instead of n! itself. The logarithm of n! fits easily in a double (unless n is huge).
Any ways to handle factorial of large numbers in C ?
As factorials can rapidly exceed the range of standard fixed width integers and even floating point types like double, Code should consider a user type that allows for unbounded integer precision for an exact answer.
Various wide integer precision libraries exist, yet if code needs a simple solution, consider using a string.
The below is not fast, nor mindful of arrays bounds, yet is illustrative of the idea. The converting of '0'-'9' to/from 0-9 so much is wasteful, yet this does allow easy step-by-step debugging.
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
static char *strfact_mult(char *s, unsigned x) {
unsigned sum = 0;
size_t len = strlen(s);
size_t i = len;
while (i > 0) {
sum += (s[--i] - '0') * x;
s[i] = sum % 10 + '0';
sum /= 10;
}
while (sum) {
len++;
memmove(&s[1], s, len);
s[i] = sum % 10 + '0';
sum /= 10;
}
return s;
}
char *str_fact(char *dest, unsigned n) {
strcpy(dest, "1");
while (n > 1) {
strfact_mult(dest, n--);
}
return dest;
}
void test_fact(unsigned n) {
char s[1000];
printf("%3u %s\n", n, str_fact(s, n));
}
int main(void) {
test_fact(0);
test_fact(4);
test_fact(54);
test_fact(100);
}
Output
0 1
4 24
54 230843697339241380472092742683027581083278564571807941132288000000000000
100 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
Here is a solution for your question:
#include <stdio.h>
void factorial(int b){
int temp = 0, r, size = 0, x;
int arr[200] = {0};
int l_b = b-1;
while(b>0){
r = b%10;
arr[size++] = r;
b = b/10;
}
while(l_b >= 2){
int i=0;
while(size>0){
x = arr[i]*l_b+temp ;
arr[i++] = x%10;
temp = x/10;
size--;
}
while(temp>0){
arr[i++] = temp%10;
temp = temp/10;
}
size = i; --l_b;
}
for(int k=size-1;k>=0;k--)
printf("%d",arr[k]);//ok i'm taking space here
printf("\n");
}
int main(void) {
// your code goes here
int fact;
scanf("%d\n",&fact);
factorial(fact);
return 0;
}
Factorials up to 12! fit into a 32-bit integer. Factorials up to 20! fit into a 64-bit integer. After that, you've run out of bits on most machines. However, 34! fits into an unsigned 128-bit integer, 57! fits into a 256-bit integer, and 98! fits into an unsigned 512-bit integer. To calculate 100! as an integer, you need at least 525 bits.
This bc script calculates factorials (up to 35! but you can change the limit easily):
#!/usr/bin/bc -l
define f(n) {
auto r, i
r = 1
for (i = 1; i <= n; i++)
{
r *= i;
print "n = ", i, ", log2 = ", l(r)/l(2), ", n! = ", r, "\n"
}
}
f(35)
quit
And some sample values:
# Key values
# n = 1, log2 = 0.00000000000000000000, n! = 1
# n = 2, log2 = 1.00000000000000000000, n! = 2
# n = 3, log2 = 2.58496250072115618147, n! = 6
# n = 4, log2 = 4.58496250072115618149, n! = 24
# n = 5, log2 = 6.90689059560851852938, n! = 120
# n = 6, log2 = 9.49185309632967471087, n! = 720
# n = 7, log2 = 12.29920801838727881834, n! = 5040
# n = 8, log2 = 15.29920801838727881836, n! = 40320
# n = 9, log2 = 18.46913301982959118130, n! = 362880
# n = 10, log2 = 21.79106111471695352921, n! = 3628800
# n = 11, log2 = 25.25049273335425078544, n! = 39916800
# n = 12, log2 = 28.83545523407540696694, n! = 479001600
# n = 13, log2 = 32.53589495221649912738, n! = 6227020800
# n = 14, log2 = 36.34324987427410323486, n! = 87178291200
# n = 15, log2 = 40.25014046988262176421, n! = 1307674368000
# n = 16, log2 = 44.25014046988262176426, n! = 20922789888000
# n = 17, log2 = 48.33760331113296117256, n! = 355687428096000
# n = 18, log2 = 52.50752831257527353551, n! = 6402373705728000
# n = 19, log2 = 56.75545582601885902935, n! = 121645100408832000
# n = 20, log2 = 61.07738392090622137726, n! = 2432902008176640000
# n = 21, log2 = 65.46970134368498166621, n! = 51090942171709440000
# ...
# n = 34, log2 = 127.79512061296909618950, n! = 295232799039604140847618609643520000000
# n = 35, log2 = 132.92440362991406264487, n! = 10333147966386144929666651337523200000000
# ...
# n = 57, log2 = 254.48541573017643505939
# n = 58, log2 = 260.34339672530400718017
# ...
# n = 98, log2 = 511.49178048020535201128
# n = 99, log2 = 518.12113710028496163045
# n = 100, log2 = 524.76499329005968632625
For the factorials 57!, 58!, 98!, 99!, 100! I've omitted the factorial value as it spreads over multiple lines in the output and isn't all that important. Note that 100! requires at least 525 bits of precision.
This code is available in my SOQ (Stack Overflow Questions) repository on GitHub as file factorial.bc in the src/miscellany sub-directory.
You could use double or long double to extend the range of values, but you lose some accuracy.
This is most certainly due to overflow. You need a way to represent large numbers (unsigned long long won't even cover up to 21!).
I guess that's because you are overflowing the int range, which is up to approx. 2 billions. You can get up to 4 billions if you use unsigned int, but beyond that you have to use the bigint library.
100! = 933262154439441526816992388562667004907159682643816214685929
6389521759999322991560894146397156518286253697920827223758251185210
916864000000000000000000000000
You can't represent a number this big with an int or a long.
In addition to the advice of others, I'd suggest getting familiar with the storage limits of the basic types (int, long, long long, ...) for whatever computer/platform you're actually using. ("When in doubt, print more out!")
One earlier poster referred to an 80-bit precision limit, but that's particular to an x86 CPU.
Another person cited ISO C90 several times, although C99 is the latest standard; even if many compilers haven't completely implemented C99, you will probably find that they very-very likely at least have support for long long, which should correspond to >= 64-bit precision.
Don't use the recursive algorithm I think, it is super slow, even if it is cached it will be slow. This is just something you should consider.
The reason for this is when you call fact(100) you don't actually run it 100 times, you actually run that function 5050 times. Which is bad, if it is cached then it could be 100 times, however, it is still slower to run a function call with if statements then to run a loop.
double print_solution(int n)
{
double rval = 1;
unsigned int i;
for( i = 1; i <= n; i++ ) {
rval *= i;
}
return rval;
}
Using arbitary-precision arithmetic you could make it go very high, however, you need to use a library to do that, or you could make your own library, but that would take a lot of time to do.