High-precision program that calculates 2^n - c

I'm building a program in C that can get powers of 2. The user inputs the value of n, and the program calculates 2^n.
Here's the code.
The problem comes when I input 100
What I am getting:
1,267,650,600,228,229,400,000,000,000,000
What I should get
1,267,650,600,228,229,401,496,703,205,376
It has to be coded entirely in ANSI C. Any ideas on how to increase the precision? The maximum value of N has to be 256 (256 bits, I imagine, which means the maximum output should be 2^256).
What I'm lacking here is precision, and I don't know how to fix that. Any ideas?

I think it's easiest if you work in base 10 from the start. This is because while calculating powers of 2 in binary is trivial, the conversion back to base 10 is a lot harder.
If you have an array of base 10 digits1, you only need to implement base 10 addition with carry to be able to multiply by 2 (by adding the number to itself). Do that n times in a loop and you have your answer.
If you wish to support higher exponents, you can also look into implementing exponentiation by squaring, but that's harder, since you'll need general multiplication, not just by 2 for that.
1 Tip: It's more convenient if you store the digits in reverse order.

Here is my quick and dirty implementation of hammar's approach., storing the decimal number as a C string with the digits in reverse order.
Run the code on ideone
void doubleDecimal(char * decimal)
{
char buffer[256] = "";
char c;
unsigned char d, carry = 0;
int i = 0;
while (c = decimal[i])
{
d = 2 * (c - '0') + carry;
buffer[i] = (d % 10) + '0';
carry = d / 10;
i++;
}
if (carry > 0)
buffer[i++] = (carry % 10) + '0';
buffer[i] = '\0';
strncpy(decimal, buffer, 256);
}
void reverse(char * str)
{
int i = 0;
int j = strlen(str) - 1;
while (j > i)
{
char tmp = str[i];
str[i] = str[j];
str[j] = tmp;
i++;
j--;
}
}
int main(void)
{
char decimal[256] = "1";
int i;
for (i = 0; i < 100; i++)
doubleDecimal(decimal);
reverse(decimal);
printf("%s", decimal);
return 0;
}
Output:
1267650600228229401496703205376

double is a (probably) 64bit value. You can't store 256 bits of precision in 64 bits. The reason that you are getting a number that is sort of close is because floating point numbers are stored with varying precision -- not all sequential numbers can be represented, but you can represent very large numbers. Pretty useless in this case.
What you want is either to use an arbitrary precision library or, since this is probably homework, you are expected to write your own.

A typical double, using 64-bit IEEE 754, has about 51 bits precision, IIRC.
Most probably the point of supporting exponents up to 256 is to exceed that precision, and also the precision of a long double or long long, so that you have to do things yourself.
As a homework exercise, then,
Store decimal digit values in an array + a digit count
Implement doubling of the value in such array + count
Start with 1 and double value appropriate number of times.

A few things you'll want to think about to solve this:
You are only dealing with integers so you should use an integer
representation (you will need to roll your own because you can't use
long long which is "only" 64 bits long).
Powers of 2 you say -how convenient - computers store numbers using powers of 2 (you'll
only need to use shift operations and bit fiddling .... no
multiplications will be needed).
How can you convert a base 2 number to a base 10 number for display purposes (think of division and outputting one number at a time (think about what a hardware divisor does in order to get the bit manipulations correct).

You can't the store 256 bits of precision in 64 bits. Reason that you are getting a number to close is because floating point numbers are stored with varying precision. To all sequential numbers can be represented, but you can represent very large numbers. Pretty useless in this case.

#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//constants
#define MAX_DIGITS 1000
//big integer number struct
struct bigint {
char Digits[MAX_DIGITS];
};
//assign a value
void assign(struct bigint* Number,int Value) {
if (Value!=1) {
printf("Can not assign value other than 1\n");
exit(0);
}
memset(Number,0,sizeof(bigint));
Number->Digits[0] = Value;
}
//multiply the big integer number with value
void multiply(struct bigint* Number,int Value) {
int Digit,New_Digit;
int Carry = 0;
for (int Index=0; Index<MAX_DIGITS; Index++) {
Digit = Number->Digits[Index];
New_Digit = Digit*Value%10;
if (New_Digit+Carry<10) {
New_Digit = New_Digit+Carry;
Carry = Digit*Value/10;
}
else {
New_Digit = (New_Digit+Carry)%10;
Carry = (Digit*Value/10)+1;
}
//set the new digit
Number->Digits[Index] = New_Digit;
}//for loop
}
//print out the value of big integer type
void print(struct bigint* Number) {
int Index = MAX_DIGITS-1;
while (Number->Digits[Index]==0 && Index>=0)
Index--;
//the big integer value is zero
if (Index==-1) {
printf("0");
return;
}
while (Index>=0) {
printf("%u",Number->Digits[Index]);
Index--;
}
}
//main programme entry point
int main(int Argc,char** Args) {
int Power = 100;
struct bigint Number;
//assign the initial value
assign(&Number,1);
//do the multiplication
for (int Index=0; Index<Power; Index++)
multiply(&Number,2);
//print result
print(&Number);
getch();
}
//END-OF-FILE

Related

Declare an Array without Size in C programming

I am writing a program that converts a given bit string (up to 32-bits) into decimal assuming the input is given in unsigned magnitude and two's complement. I am reading each bit in from the user one char at a time and attempting to store it into an array, but the array doesn't have a required size. Is there a way to get the array to go through the loop without the array size being known? I also am trying to figure out a way to not use the pow and multiplication functions. I am posting my code below, if you have any ideas please
#include "stdio.h"
#include "math.h"
#define MAX_BITS 32
#define ENTER '\n'
#define NUMBER_TWO 2
int main()
{
int unsignedMag;
int twosComp;
int negation[n];
int bitStore[n];
char enter;
//Input from the User
printf("Enter up to 32 bits (hit 'enter' to terminate early): ");
//Reads the first bit as a character
char bit = getchar();
while (getchar != enter) {
bit = bit - '0';
scanf("%c", &bitStore[bit]);
getchar();
}
//Terminates if user hits enter
if (bit == enter) {
return 0;
}
//Continue through code
else {
//Loop to calculate unsigned magnitude
for (int i = 0; i < bitStore[i]; i++) {
unsignedMag = unsignedMag + (bitStore[i] * pow(NUMBER_TWO, i));
}
//Loop to calculate complete negation
for (int j = 0; j < bitStore; j++) {
negation[j] = ~bitStore[j]
}
negation = negation + 1;
for (int l = 0; l < negation; l++) {
twosComp = twosComp + (negation[l] * pow(NUMBER_TWO, l));
}
}
return 0;
}
"Is there a way to get the array to go through the loop without the array size being known?"
No. Array sizes are fixed at the point the array is declared and the size is knownable: e.g. #Observer
size_t size = sizeof bitStore/sizeof bitStore[0];
Instead, since code has "given bit string (up to 32-bits) ", define the array as size 32 (or 33 is a string is desired).
Keep track of how much of the array was assigned.
//int bitStore[n];
int bitStore[MAX_BITS];
int count = 0;
// char bit = getchar();
int bit = getchar(); // Use `int` to account for potentially 257 different values
//while (getchar != enter) {
while (count < MAX_BITS && (bit == '0' || bit == '1')) {
bit = bit - '0';
// Do not read again, instead save result.
//scanf("%c", &bitStore[bit]);
bitStore[count++] = bit;
// getchar();
bit = getchar();
}
to not use the pow and multiplication functions.
Simply add or multiply by 2 via a shift. It is unclear why OP has a goal of not using "multiplication". I see little reason to prohibit *. A good compiler will emit efficient code when the underlying multiplication is expensive as *2 is trivial to optimize.
// int unsignedMag;
unsigned unsignedMag = 0; // initialize
// for (int i = 0; i < bitStore[i]; i++) {
for (int i = 0; i < count; i++) {
// preferred code, yet OP wants to avoid * for unclear reasons
// unsignedMag = unsignedMag*2 + bitStore[i];
unsignedMag = unsignedMag + unsignedMag + bitStore[i];
}
pow() is good to avoid for many reasons here. Most of all, using double math for an integer problem runs into precision issues with wide integers.
converts a given bit string (up to 32-bits) into decimal
Note that a bitStore[] array is not needed for this task. Simply form unsignedMag as data is read.

How to convert very large binary to decimal in C

I'm using netBean to code C, and my assignment is convert a very large binary number to decimal ( the binary number maybe upto 100 digits), I'm very confuse because my program works when the binary number is about 50-60 digits but it will automatically crash on run-time when input is larger. I'm using long long int to store the decimal result but it seem doesn't work!
Here is my code :
long long int decimal = 0;
int position = 0;
for(int i = strlen(binaryInput)-1; i>=0; --i){
if(binaryInput[i]=='1'){
decimal += (long long int)(pow(2,position));
}
++position;
}
printf("\nDecimal number is: %lli ", decimal);
'binaryInput' is my string to store binaryNumber from keyboard.
Here is a hint:
The easiest solution is to actually take the long binary number, and split it in half (or quarters, or whatever.)
Keep track of which of these is the upper range of the binary number, and which of these is the lower end of the binary number.
Calculate what the true value of the lower range, and upper range is. After that add them together.
long long int has a range of -9,223,372,036,854,775,807 to 9,223,372,036,854,775,807, as mentioned here. There is no way that 100 bits can fit in there. However, this type is signed, you could try with an unsigned one, but I do not see any assumption on your numbers to be non-negative.
You could try with int128_t which fits 128-bit signed, but this is not Standard (Why isn't there int128_t?).
Consider using an array of size 100, where each cell will store a digit. With this approach it is suggested that you use Double dabble algorithm, which is used to convert binary numbers into binary-coded decimal (BCD) notation.
If you need a library, then The GNU Multiple Precision Arithmetic Library could do the trick.
PS: Use bit-shifts instead of pow(), since it will operate on floating-point values, and will decrease the performance of your code.
Not sure if this is the most optimized technique. This can calculate up to 1000 digit. You can increase the array allocation to calculate longer binary numbers
I used strings for input and high school mathematics technique for addition and calculate the power of 2
#include <bits/stdc++.h>
typedef long long int lli;
using namespace std;
int main() {
char bin_number[1010];
//variable for big integer operation
int int_number[1010], t_int_number[500];
/*
* int_number : converted decimal number will be stored here
* t_int_number : will be used to calculate the power of 2
*/
int bin_length, t_int_length, int_length, index;
/*
* bin_length : length(bin_number)
* t_int_length : length(t_int_length)
* int_length : length(int_length)
*/
bool carry;
while(scanf("%s", bin_number) != EOF) { //input binary number
for (int i = 0; i < 500; i++) { //intialize decimal number to 0 and t_int_number to 0
int_number[i] = 0;
t_int_number[i] = 0;
}
//set t_int_number to 1
t_int_number[0] = 1;
t_int_length = 1;
//set the int_number to 0
int_length = 1;
index = 0;
//calculate input length
bin_length = strlen(bin_number);
for (int i = bin_length - 1; i >= 0; i--) { //checks each digit of binary number
//if the digit in binary representation is 1
if (bin_number[i] == '1') {
//sum (int_number, t_int_number)
for (int index = 0; index < t_int_length; index++) {
int_number[index] +=
t_int_number[index]; //sum t_int_number digits
if (int_number[index] > 9) { //if carry
int_number[index + 1] ++;
int_number[index] -= 10;
}
}
int_length = index;
if (int_number[index] != 0) { //i f length increase for addition
int_length ++;
}
}
//Being ready for next iteration
//multiplying everytime with 2 and save it to t_int_number
carry = false;
for (index = 0; index < t_int_length; index++) {
t_int_number[index] += t_int_number[index]; //double the number
}
for (index = 0; index < t_int_length; index++) {
if (t_int_number[index] > 9) {
t_int_number[index] -= 10;
t_int_number[index + 1]++;
}
}
if (t_int_number[index] != 0) {
t_int_length++;
}
}
//printing the decimal number
for (int i = int_length - 1; i >=0; i--) {
printf("%d", int_number[i]);
}
printf("\n");
}
return 0;
}

Decompose decimal part of a double

I need to decompose a decimal part of a number in single digits, but I need to get the most obvious representation. Here is my code, to be clearer :
#include <stdio.h>
void main(){
double value = 0.123;
int decim_tab[6];
int decimal;
int i;
for (i = 0; i < 6; ++i) {
value *= 10;
decimal = (int)value;
decim_tab[i] = decimal;
value -= decimal;
}
for (i = 0; i < 6; ++i)
print("%d\n", decim_tab[i]);
}
The output I need is :
1
2
3
0
0
0
But I get :
1
2
2
9
9
9
EDIT
A solution I found is to add a small delta to the value in order to force the shortest representation :
#include <stdio.h>
void main(){
double value = 0.123;
int decim_tab[6];
int decimal;
int i;
value += 0.000000001
for (i = 0; i < 6; ++i) {
value *= 10;
decimal = (int)value;
decim_tab[i] = decimal;
value -= decimal;
}
for (i = 0; i < 6; ++i)
print("%d\n", decim_tab[i]);
}
I would be happy to find a better way, any suggestions ?
The reason you get unexpected output is that decimal fractions cannot always be exactly represented using (most common) base two floating point numbers. Using printf("%.20f", value); after your assignment of value you will see that the value 0.123 is actually being stored as 0.12299..., which is why you receive that output.
If you only need to print out six digits, you can use string formatting of floating point numbers:
#include <stdio.h>
#include <stdlib.h>
int main(){
double value = 0.123;
char *s = malloc(9);
sprintf(s++, "%.6f", value);
while(*s++){
putchar(*s);
putchar('\n');
}
}
EDIT: The code in my answer is very specific to the example you gave, so when using it be aware that I made some assumptions, e.g. your value will never have more than one digit before the decimal point.
If you want 6 decimal places, you should add 0.0000005 (ie 0.5e-6) to round the value to the nearest place. This method will work for positive numbers, first extract the sign, then work on the absolute value.
Floating point numbers are not exact value representation. Here's a simple sample:
double a = 0.15 + 0.15; // 0.15 + 0.15 == 0.3, right?
double b = 0.1 + 0.2; // 0.1 + 0.2 == 0.3, right?
if (a == b) {
printf("Equal\n");
} else {
printf("Unequal\n");
}
What will that print? Equal? Are you sure? Try it yourself:
http://rextester.com/VZOZ1043
It prints Unequal, that's because there are some numbers that floating point can't represent exactly and that's something you always need to keep in mind when doing floating point math. Also there is rounding involved in many operations, so the results of math operations are as good as possible but not always "exact", there's a tiny error that can also sum up if you run multiple operations.
double value = 0.123;
// Assuming none of your numbers has more than 58 digits,
// one period and one termination char.
char buffer[60];
// Print the number to the buffer.
// Missing: Error checking if it did fit!
snprintf(buffer, sizeof(buffer), "%f", value);
// Find the period or end of string
int idx = 0;
for (; buffer[idx] && buffer[idx] != '.'; idx++);
// Print anything after the period till
// the end of the string
if (buffer[idx] == '.') {
for (idx++; buffer[idx]; idx++) {
printf("%c\n", buffer[idx]);
}
}
Test it: http://rextester.com/CYDQO24769

How to sum digits before and after decimal point separately in C?

I'm supposed to get a decimal number and sum the whole part digits separately and the decimal part separately,
so for example if I get:
1321.0365
the output should be: 7.14
I'm supposed to do that without using arrays.
this is what I tried to do by far, after getting the number from a function, first separating both parts, then multiplying the decimal number by 10, until the number is equal to the int part.
then I tried to sum each of the parts separately, and after i do that, divide the decimal part until the number is equal to the int number.
theoretically it sounds like it should work, but I think I miss something on the way.
this is what I've done so far:
double number;
double sumReal=0;
int wholePart;
int sumWhole=0;
int multiply=1;
number=getDecimalNumber();
wholePart=number;
number-=wholePart;
while(number!=(int)number)
number*=10;
while (number!=0)
{
sumReal+=(int)number%10;
number/=10;
}
while (wholePart!=0)
{
sumWhole+=(int)wholePart%10;
wholePart/=10;
}
while(sumReal!=(int)sumReal)
sumReal/10;
number=wholePart+sumReal;
somehow most of the parts seem to work, but multiplying the real part by 10 always gets me 0, and when summing the real part and the whole number at the end also gets me 0, which leads me to a 0 output.
#include <stdio.h>
int main(){
int ch;
int n1 = 0, n2 = 0;
while((ch=getchar())!= '.'){
n1 += ch - '0';
}
while((ch=getchar())!= '\n'){
n2 += ch - '0';
}
printf("%d.%d\n", n1, n2);
return 0;
}
It's easier to go this way :
use the number as string (get a char* pointer on the string so you don't actively use an array)
split on the decimal point separator
(you get two char* pointers, one per string)
iterate on one string char by char (increment the pointer), convert the current char in int and add
same with second string
you're done
I strongly suspect it is what your teacher want you to do, more than exotic calculations.
here is one way to write the algorithm
It may still have bugs that will need the OPs attention
#include <math.h>
// prototypes
double getDoubleNumber(void);
double sumOfDigits( void );
double sumOfDigits()
{
double doubleNumber = 0.0;
double wholePart;
double fractionPart;
int sumWhole=0;
int sumFraction = 0;
double sumParts=0.0;
// get the original number
doubleNumber=getDoubleNumber();
wholePart = trunc(doubleNumber);
// calc fractional part
fractionPart = doubleNumber - wholePart;
// this may need modification due to inexact representation of value
// move fractionPart to left of decimal point
while(fractionPart > floor(fractionPart) )
{
fractionPart *= 10.0;
}
while( trunc(fractionPart) )
{
sumFraction += trunc( fmod( fractionPart, 10.0);
fractionPart /= 10.0;
}
// move fractionPart back to right of decimal point
while( trunc(sumFraction) )
{
sumFraction /= 10.0;
}
// calc sum of whole part digits
while ( trunc(wholePart) )
{
sumWhole += trunc( fmod( wholePart, 10.0 ) );
wholePart /= 10.0;
}
sumParts = sumWhole+sumFraction;
return( sumParts );
} // end function: sumOfDigits

Converting int to int[] in 'C'

I basically want to convert a given int number and store individual digits in an array for further processing.
I know I can use % and get each digit and store it. But the thing is if I do not know the number of digits of the int till runtime and hence I cannot allocate the size of the array. So, I cannot work backwards (from the units place).
I also do not want to first store the number backwords in an array and then again reverse the array.
Is there any other way of getting about doing this?
Eg: int num = 12345;
OUTPUT: ar[0] = 1, ar[1] = 2 and so on, where ar[] is an int array.
Convert is probably not the right word. You can take the int, dynamically allocate a new int[], and then store the digits of the int into the int[]. I'm using log base 10 to calculate how many digits num has. Include math.h to use it. The following code is untested, but will give you an idea of what to do.
int num = 12345;
int size = (int)(log10(num)+1);
// allocate array
int *digits = (int*)malloc(sizeof(int) * size);
// get digits
for(int i=size-1; i>=0; --i) {
digits[i] = num%10;
num=num/10; // integer division
}
The easiest way is to calculate number of digits to know the size of an array you need
int input = <input number>; // >= 0
int d, numdigits = 1;
int *arr;
d = input;
while (d /= 10)
numdigits++;
arr = malloc(sizeof(int) * numdigits);
There's even easier way: probably you pass a number to your program as an argument from command line. In this case you receive it as a string in argp[N], so you can just call strlen(argp[N]) to determine number of digits in your number.
If you have a 32-bit integer type, the maximum value will be comprised of 10 digits at the most (excluding the sign for negative numbers). That could be your upper limit.
If you need to dynamically determine the minimum sufficient size, you can determine that with normal comparisons (since calling a logarithmic function is probably more expensive, but a possibility):
size = 10;
if (myint < 1000000000) size--;
if (myint < 100000000) size--;
/* ... */
Declaring the array to be of a dynamic size depends on the C language standard you are using. In C89 dynamic array sizes (based on values calculated during run-time) is not possible. You may need to use dynamically allocated memory.
HTH,
Johan
The following complete program shows one way to do this. It uses unsigned integers so as to not have to worry about converting - you didn't state what should happen for negative numbers so, like any good consultant, I made the problem disappear for my own convenience :-)
It basically works out the required size of an array and allocates it. The array itself has one element at the start specifying how many elements are in the array (a length int).
Each subsequent element is a digit in sequence. The main code below shows how to process it.
If it can't create the array, it'll just give you back NULL - you should also remember to free the memory passed back once you're done with it.
#include <stdio.h>
#include <stdlib.h>
int *convert (unsigned int num) {
unsigned int *ptr;
unsigned int digits = 0;
unsigned int temp = num;
// Figure out how many digits in the number.
if (temp == 0) {
digits = 1;
} else {
while (temp > 0) {
temp /= 10;
digits++;
}
}
// Allocate enough memory for length and digits.
ptr = malloc ((digits + 1) * sizeof (unsigned int));
// Populate array if we got one.
if (ptr != NULL) {
ptr[0] = digits;
for (temp = 0; temp < digits; temp++) {
ptr[digits - temp] = num % 10;
num /= 10;
}
}
return ptr;
}
That convert function above is the "meat" - it allocates an integer array to place the length (index 0) and digits (indexes 1 through N where N is the number of digits). The following was the test program I used.
int main (void) {
int i;
unsigned int num = 12345;
unsigned int *arr = convert (num);
if (arr == NULL) {
printf ("No memory\n");
} else {
// Length is index 0, rest are digits.
for (i = 1; i <= arr[0]; i++)
printf ("arr[%d] = %u\n", i, arr[i]);
free (arr);
}
return 0;
}
The output of this is:
arr[1] = 1
arr[2] = 2
arr[3] = 3
arr[4] = 4
arr[5] = 5
You can find out the number of digits by taking the base-10 logarithm and adding one. For that, you could use the log10 or log10f functions from the standard math library. This may be a bit slower, but it's probably the most exact as long as double has enough bits to exactly represent your number:
int numdigits = 1 + log10(num);
Alternatively, you could repeatedly divide by ten until the result is zero and count the digits that way.
Still another option is just to allocate enough room for the maximum number of digits the type can have. For a 32-bit integer, that'd be 10; for 64-bit, 20 should be enough. You can just zero the extra digits. Since that's not a lot of wasted space even in the worst case, it might be the simplest and fastest option. You'd have to know how many bits are in an int in your setup, though.
You can also estimate fairly well by allocating 3 digits for each 10 bits used, plus one. That should be enough digits unless the number of bits is ridiculously large (way above the number of digits any of the usual int types could have).
int numdigits = 1
unsigned int n = num;
for (n = num; n & 0x03ff; n >>= 10)
numdigits += 3;
/* numdigits is at least the needed number of digits, maybe up to 3 more */
This last one won't work (directly) if the number is negative.
What you basically want to do is to transform your integer to an array of its decimal positions. The printf family of functions perfectly knows how to do this, no need to reinvent the wheel. I am changing the assignment a bit since you didn't say anything about signs, and it simply makes more sense for unsigned values.
unsigned* res = 0;
size_t len = 0;
{
/* temporary array, large enough to hold the representation of any unsigned */
char positions[20] = { 0 };
sprintf(position, "%u", number);
len = strlen(position);
res = malloc(sizeof(unsigned[len]));
for (size_t i = 0; i < len; ++i)
res[i] = position[i] - '0';
}

Resources