Let's say I have a very large number represented using an array of unsigned long(int64), and I want to see its base10 form either stored in a string and/or display it to the standard out directly, how would I do that in C or C++ without using libraries like gmp or boost?, what algorithm or method should I know?
below is an example base2^64 number, with its base10 value in the comment
// base2^64
unsigned long big_num[3] = [77478, 656713, 872];
// base10 = 26364397224300470284329554475476558257587048
I don't exactly know if this is the correct way to convert another number base to base 10, but this is what I did:
To get the base10 value 26364397224300470284329554475476558257587048, I summed up all the digits of the base2^64 number that is multiplied to its base and raised by the index of the digit.
base10 = ((77478 * ((2^64)^2)) + ((656713 * ((2^64)^1))) + ((872 * ((2^64)^0))))
= 26364397224300470284329554475476558257587048
the only problem with this is that there is no primitive data type that can hold this super large sum...
I was just thinking if libraries like boost cpp_int and gmp represents their number like this, and if yes how do they convert it to it's base10 value in string form or display the base10 value in standard out?
Or do they just use half of the bits of the data types that they use like for example in unsigned long and maybe use something like base 10000?
Repeatedly "mod 10" the array to find the next least significant decimal digit, then "divide by 10". Repeat as needed.
Avoid unsigned long to encode 64-bit values as it may be only 32-bit.
If code can encode the number not using the widest type and use uin32_t, then doing the repeated "mod 10" of the array is not so hard.
Below illustrative code still needs to reverse the string - something left for OP. Potential other warts too - hence the advantage of using big number libraries for this sort of thing.
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
// Form reverse decimal string
void convert(char dec[], size_t n, uint32_t b32[]) {
// TBD code to handle 0
while (n > 0 && b32[0] == 0) {
b32++;
n--;
}
while (n > 0) {
unsigned char rem = 0;
// Divide by 10.
for (size_t i = 0; i < n; i++) {
uint64_t sum = rem * (1ULL << 32) + b32[i];
b32[i] = (uint32_t) (sum / 10u);
rem = (unsigned char) (sum % 10u);
}
*dec++ = (char) (rem + '0');
if (b32[0] == 0) {
b32++;
n--;
}
}
*dec = 0;
}
Sample
int main() {
// unsigned long big_num[3] = [77478, 656713, 872];
uint32_t big_num[6] = {0, 77478, 0, 656713, 0, 872};
size_t n = sizeof big_num / sizeof big_num[0];
char s[sizeof big_num * 10 + 1];
convert(s, n, big_num);
printf("<%s>\n", s);
// <84078575285567457445592348207400342279346362>
// 26364397224300470284329554475476558257587048
}
To get the decimal representation of this number, you need to repeatedly divide the number by 10 and take the remainder to get the decimal digits. This means you need to implement long division for big numbers, which also requires implementing long addition, subtraction, and multiplication.
That's a lot of code that big number libraries give you, so just use one.
I have a big hexadecimal number, for example CD4A0619FB0907BC00000 (25!) or any other number like this. Now, using standard C/C++ code only (no libraries like Boost), I want to convert this number to the decimal number 15511210043330985984000000. Unfortunately, it's too big for a 64 bit integer (like long long) and I don't want to use any floating point data types either. If this is possible at all, how can you do this?
Assuming you don't want to use any of resources that might fit your description "libraries like Boost". The simple answer is to write your own subset of one, with just the operations you need.
If 32 hex digits is enough, then simplest would be to create your own 128 bit unsigned int and code a divide by 10 function (producing quotient and remainder) for that 128-bit int. You really don't need any other functions and divide by 10 is pretty easy. Converting up to 32 hex digits to 128 bit int is trivial and generating decimal output from a series of divide by ten is trivial.
If you want essentially unlimited size, then it is likely simpler to represent a decimal number as a string of digits and write a routine to multiply that by 16 and add in another digit. That would never be the efficient solution, just likely easier to code for your purpose and unlimited size.
vector<unsigned int> bin2dec(vector<unsigned int> binary)
{
vector<unsigned int> decimal;
bool all_zero = false;
// binary[i]: stores 8-bit of the nubmer.
// Ex. 258 = 0x102 => binary[0] = 0x2, binary[1] = 0x1.
while (!all_zero) {
all_zero = true;
for (int i = binary.size() - 1; i >= 0; i--) {
int q = binary[i] / 10;
int r = binary[i] % 10;
binary[i] = q;
if (i > 0) {
binary[i-1] += (r << 8);
} else {
decimal.insert(decimal.begin(), r);
}
if (q != 0) {
all_zero = false;
}
}
}
// each element stands for one digit of the decimal number.
// Ex. 258 => decimal[0] = 2, decimal[1] = 5, decimal[2] = 8.
return decimal;
}
If you don't want to use external libraries then you will have to implement a arbitary-precision integer type yourself. See this question for ideas on how to do this. You will also need a function/constructor for converting hexadecimal strings to your new type. See this question for ideas on how to do this.
So I've made this function on an AVR microcontroller that works OKish, but when I call
display(1)
the value shown on the 4 digit display is "1.099" instead of "1.000".
void display(float n) {
int8_t i, digit_pos=0;
unsigned short digit;
PORTC &= ~((1<<MUX_A2) | (1<<MUX_B2) | (1<<MUX_E2));
ENABLE_DISPLAY;
for (i=3;i>=-3;i--)
{
digit = n/pow(10,i);
digit = digit%10;
if (digit==0&&i>0&&digit_pos==0)
continue;
if (digit_pos-i<3)
if (i==0)
digit += 10;
PORTD = SegCode[digit];
PORTC = ((PORTC & (~(3<<MUX_A2))) | (digit_pos<<MUX_A2)) & ~(1<<MUX_E2);
PORTC |= (1<<MUX_E2);
if (digit_pos==3)
break;
else
digit_pos++;
}
PORTD=0x00;
}
The "n" variable, which is supposed to be shown, is a float, so why is the precision lost starting with the second decimal during
digit = n/pow(10,i);
digit = digit%10;
Is it because of type conversion? Is it because of some 8bit RISC processor limitation?
It's because of type conversion.
float is not precise, so when you do 1/.01 and 1/.001 in floating point, you get slightly less than 100 and 1000. (I didn't want to trace your code all that thoroughly, but that is where the problem lies.) This is rounded down to 99 and 999, which is why the 9s show up in the output.
You would be much better off to work in integers, if you can. Prevent rounding down by adding half the value of the last expected digit.
It seems like you are expecting values between 0.001 and 9999. A quick implementation would use cases:
if (n > 9999) error
else if (n >= 1000) {dec = (int)(n + 0.5); shift = 0;}
else if (n >= 100) {dec = (int)(10*(n + 0.05)); shift = 1;}
and so on
then do stuff with dec
Another tip, you don't need to use the % operator. Compute the digits from the right and store them before displaying.
dec_next = dec / 10;
digit = dec - 10*dec_next;
dec = dec_next;
digit is declared as an unsigned short, so any decimal value assigned to it will be truncated. The division you are doing yields a float value which you are trying to store in digit, so it will be truncated to be stored as an unsigned short.
You will probably want to change the type of digit to a float if you can spare the space.
I have a little problem when assigning a result to a variable, this is happening the first time to me now. I call Convert() with "aaa" as a parameter, here is my output:
aaa
**676** *(value from cout)* = 26^(3-1)*1 **675** *(value of the variable)*
+26 = 26^(3-2)*1 700
+1 = 26^(3-3)*1 701
701
And here the code:
string alphabet="abcdefghijklmnopqrstuvwxyz";
unsigned long long Convert(string &str){
unsigned long long wvalue=0;
for(int i=0;i<str.size();++i){
size_t found=alphabet.find(str[i]);
if(found==string::npos)
cout<<"Please enter only lowercase letters of the english alphabet!"<<endl;
unsigned long long add=((found+1)*pow(26,(str.size()-(i+1))));
wvalue+=add;
if(i>0)cout<<"+";
cout<<"\t"<<((found+1)*pow(26,(str.size()-(i+1))))<<" = "<<"26^("<<str.size()<<"-"<<(i+1) <<")*"<<(found+1)<<"\t"<<wvalue<<endl;
}
return wvalue;
}
Chances are I'm missing something awfully obvious, but I cannot figure it out.
((found+1)*pow(26,(str.size()-(i+1))))
is doing the calculation, and it is doing as it is supposed to, the result within the cout-statment is correct. But the variable is substracted by 1 in the first two assignments.
pow is a floating-point function. It takes and returns floating point numbers. Assigning a floating-point number to an integer variable truncates it to an integer number, so it might have been 675.9999999 just before the assignment, which will turn into 675 when assigned to the integer variable add.
cout also rounds floating-point numbers, depending on the configuration for example to 6 significant digits. 676.0 is a better approximation than 675.999, so you see 676 in the output.
Since you don't want to calculate with real numbers but only with integral numbers, you better stay with integral functions. To take 26 to the power of n, better use multiplication n times. Since you already use a loop, and like to have the next power of 26 for every character, the best is to add a variable in which you keep the current power value, like this:
unsigned long long currentFactor = 1;
for (...) {
...
unsigned long long add = currentFactor * (found+1);
wvalue += add;
currentFactor *= 26;
}
Also note that you don't have to find the character in an alphabet string. You can also just use character arithmetic to do this:
int charNumber(char c) {
if (c >= 'a' && c <= 'z')
return c - 'a'; // calculate the position of c relative to 'a'
else
return -1; // error
}
Lets say that input from the user is a decimal number, ex. 5.2155 (having 4 decimal digits). It can be stored freely (int,double) etc.
Is there any clever (or very simple) way to find out how many decimals the number has? (kinda like the question how do you find that a number is even or odd by masking last bit).
Two ways I know of, neither very clever unfortunately but this is more a limitation of the environment rather than me :-)
The first is to sprintf the number to a big buffer with a "%.50f" format string, strip off the trailing zeros then count the characters after the decimal point. This will be limited by the printf family itself. Or you could use the string as input by the user (rather than sprintfing a floating point value), so as to avoid floating point problems altogether.
The second is to subtract the integer portion then iteratively multiply by 10 and again subtract the integer portion until you get zero. This is limited by the limits of computer representation of floating point numbers - at each stage you may get the problem of a number that cannot be represented exactly (so .2155 may actually be .215499999998). Something like the following (untested, except in my head, which is about on par with a COMX-35):
count = 0
num = abs(num)
num = num - int(num)
while num != 0:
num = num * 10
count = count + 1
num = num - int(num)
If you know the sort of numbers you'll get (e.g., they'll all be 0 to 4 digits after the decimal point), you can use standard floating point "tricks" to do it properly. For example, instead of:
while num != 0:
use
while abs(num) >= 0.0000001:
Once the number is converted from the user representation (string, OCR-ed gif file, whatever) into a floating point number, you are not dealing with the same number necessarily. So the strict, not very useful answer is "No".
If (case A) you can avoid converting the number from the string representation, the problem becomes much easier, you only need to count the digits after the decimal point and subtract the number of trailing zeros.
If you cannot do it (case B), then you need to make an assumption about the maximum number of decimals, convert the number back into string representation and round it to this maximum number using the round-to-even method. For example, if the user supplies 1.1 which gets represented as 1.09999999999999 (hypothetically), converting it back to string yields, guess what, "1.09999999999999". Rounding this number to, say, four decimal points gives you "1.1000". Now it's back to case A.
Off the top of my head:
start with the fractional portion: .2155
repeatedly multiply by 10 and throw away the integer portion of the number until you get zero. The number of steps will be the number of decimals. e.g:
.2155 * 10 = 2.155
.155 * 10 = 1.55
.55 * 10 = 5.5
.5 * 10 = 5.0
4 steps = 4 decimal digits
Something like this might work as well:
float i = 5.2154;
std::string s;
std::string t;
std::stringstream out;
out << i;
s = out.str();
t = s.substr(s.find(".")+1);
cout<<"number of decimal places: " << t.length();
What do you mean "stored freely (int"? Once stored in an int, it has zero decimals left, clearly. A double is stored in a binary form, so no obvious or simple relation to "decimals" either. Why don't you keep the input as a string, just long enough to count those decimals, before sending it on to its final numeric-variable destination?
using the Scientific Notation format (to avoid rounding errors):
#include <stdio.h>
#include <string.h>
/* Counting the number of decimals
*
* 1. Use Scientific Notation format
* 2. Convert it to a string
* 3. Tokenize it on the exp sign, discard the base part
* 4. convert the second token back to number
*/
int main(){
int counts;
char *sign;
char str[15];
char *base;
char *exp10;
float real = 0.00001;
sprintf (str, "%E", real);
sign= ( strpbrk ( str, "+"))? "+" : "-";
base = strtok (str, sign);
exp10 = strtok (NULL, sign);
counts=atoi(exp10);
printf("[%d]\n", counts);
return 0;
}
[5]
If the decimal part of your number is stored in a separate int, you can just count the its decimal digits.
This is a improvement on andrei alexandrescu's improvement. His version was already faster than the naive way (dividing by 10 at every digit). The version below is constant time and faster at least on x86-64 and ARM for all sizes, but occupies twice as much binary code, so it is not as cache-friendly.
Benchmarks for this version vs alexandrescu's version on my PR on facebook folly.
Works on unsigned, not signed.
inline uint32_t digits10(uint64_t v) {
return 1
+ (std::uint32_t)(v>=10)
+ (std::uint32_t)(v>=100)
+ (std::uint32_t)(v>=1000)
+ (std::uint32_t)(v>=10000)
+ (std::uint32_t)(v>=100000)
+ (std::uint32_t)(v>=1000000)
+ (std::uint32_t)(v>=10000000)
+ (std::uint32_t)(v>=100000000)
+ (std::uint32_t)(v>=1000000000)
+ (std::uint32_t)(v>=10000000000ull)
+ (std::uint32_t)(v>=100000000000ull)
+ (std::uint32_t)(v>=1000000000000ull)
+ (std::uint32_t)(v>=10000000000000ull)
+ (std::uint32_t)(v>=100000000000000ull)
+ (std::uint32_t)(v>=1000000000000000ull)
+ (std::uint32_t)(v>=10000000000000000ull)
+ (std::uint32_t)(v>=100000000000000000ull)
+ (std::uint32_t)(v>=1000000000000000000ull)
+ (std::uint32_t)(v>=10000000000000000000ull);
}
Years after the fight but as I have made my own solution in three lines :
string number = "543.014";
size_t dotFound;
stoi(number, &dotFound));
string(number).substr(dotFound).size()
Of course you have to test before if it is really a float
(With stof(number) == stoi(number) for example)
int main()
{
char s[100];
fgets(s,100,stdin);
unsigned i=0,sw=0,k=0,l=0,ok=0;
unsigned length=strlen(s);
for(i=0;i<length;i++)
{
if(isprint(s[i]))
{
if(sw==1)
{
k++;
if(s[i]=='0')
{
ok=0;
}
if(ok==0)
{
if(s[i]=='0')
l++;
else
{
ok=1;
l=0;
}
}
}
if(s[i]=='.')
{
sw=1;
}
}
}
printf("%d",k-l);
return 0;
}
This is a robust C++ 11 implementation suitable for float and double types:
template <typename T>
std::enable_if_t<(std::is_floating_point<T>::value), std::size_t>
decimal_places(T v)
{
std::size_t count = 0;
v = std::abs(v);
auto c = v - std::floor(v);
T factor = 10;
T eps = std::numeric_limits<T>::epsilon() * c;
while ((c > eps && c < (1 - eps)) && count < std::numeric_limits<T>::max_digits10)
{
c = v * factor;
c = c - std::floor(c);
factor *= 10;
eps = std::numeric_limits<T>::epsilon() * v * factor;
count++;
}
return count;
}
It throws the value away each iteration and instead keeps track of a power of 10 multiplier to avoid rounding issues building up. It uses machine epsilon to correctly handle decimal numbers that cannot be represented exactly in binary such as the value of 5.2155 as stipulated in the question.
Based on what others wrote, this has worked well for me. This solution does handle the case where a number can't be represented exactly in binary.
As suggested by others, the condition for the while loop indicates the precise behavior. My update uses the machine epsilon value to test whether the remainder on any loop is representable by the numeric format. The test should not compare to 0 or a hardcoded value like 0.000001.
template<class T, std::enable_if_t<std::is_floating_point_v<T>, T>* = nullptr>
unsigned int NumDecimalPlaces(T val)
{
unsigned int decimalPlaces = 0;
val = std::abs(val);
val = val - std::round(val);
while (
val - std::numeric_limits<T>::epsilon() > std::numeric_limits<T>::epsilon() &&
decimalPlaces <= std::numeric_limits<T>::digits10)
{
std::cout << val << ", ";
val = val * 10;
++decimalPlaces;
val = val - std::round(val);
}
return val;
}
As an example, if the input value is 2.1, the correct solution is 1. However, some other answers posted here would output 16 if using double precision because 2.1 can't be precisely represented in double precision.
I would suggest reading the value as a string, searching for the decimal point, and parsing the text before and after it as integers. No floating point or rounding errors.
char* fractpart(double f)
{
int intary={1,2,3,4,5,6,7,8,9,0};
char charary={'1','2','3','4','5','6','7','8','9','0'};
int count=0,x,y;
f=f-(int)f;
while(f<=1)
{
f=f*10;
for(y=0;y<10;y++)
{
if((int)f==intary[y])
{
chrstr[count]=charary[y];
break;
}
}
f=f-(int)f;
if(f<=0.01 || count==4)
break;
if(f<0)
f=-f;
count++;
}
return(chrstr);
}
Here is the complete program
#include <iostream.h>
#include <conio.h>
#include <string.h>
#include <math.h>
char charary[10]={'1','2','3','4','5','6','7','8','9','0'};
int intary[10]={1,2,3,4,5,6,7,8,9,0};
char* intpart(double);
char* fractpart(double);
int main()
{
clrscr();
int count = 0;
double d = 0;
char intstr[10], fractstr[10];
cout<<"Enter a number";
cin>>d;
strcpy(intstr,intpart(d));
strcpy(fractstr,fractpart(d));
cout<<intstr<<'.'<<fractstr;
getche();
return(0);
}
char* intpart(double f)
{
char retstr[10];
int x,y,z,count1=0;
x=(int)f;
while(x>=1)
{
z=x%10;
for(y=0;y<10;y++)
{
if(z==intary[y])
{
chrstr[count1]=charary[y];
break;
}
}
x=x/10;
count1++;
}
for(x=0,y=strlen(chrstr)-1;y>=0;y--,x++)
retstr[x]=chrstr[y];
retstr[x]='\0';
return(retstr);
}
char* fractpart(double f)
{
int count=0,x,y;
f=f-(int)f;
while(f<=1)
{
f=f*10;
for(y=0;y<10;y++)
{
if((int)f==intary[y])
{
chrstr[count]=charary[y];
break;
}
}
f=f-(int)f;
if(f<=0.01 || count==4)
break;
if(f<0)
f=-f;
count++;
}
return(chrstr);
}
One way would be to read the number in as a string. Find the length of the substring after the decimal point and that's how many decimals the person entered. To convert this string into a float by using
atof(string.c_str());
On a different note; it's always a good idea when dealing with floating point operations to store them in a special object which has finite precision. For example, you could store the float points in a special type of object called "Decimal" where the whole number part and the decimal part of the number are both ints. This way you have a finite precision. The downside to this is that you have to write out methods for arithmetic operations (+, -, *, /, etc.), but you can easily overwrite operators in C++. I know this deviates from your original question, but it's always better to store your decimals in a finite form. In this way you can also answer your question of how many decimals the number has.