Converting remainder of a floating point float/double into an int - c++

I have a double (or float) number x:
x = 1234.5678;
Now, the question is, how do break down the number into 2 int's whereas int1 would get the number before the point, and int2 is the number after the point.
The first part is easy, which we can either cast, or take a round or ceiling to get the first part into an int, I am looking for the second part to become int2=5678 without any floating points there.
i.e. to to extend the above example:
float x = 1234.5678;
int x1 = (int) x; // which would return 1234 great.
int x2 = SomeFunction????(x); // where I need x2 to become = 5678
Notice the 5678 should not have any points there.
It would be nice to hear from you.
Thanks
Heider

Here are two ways of doing it.
The first one uses std::stringstream, std::string and std::strtol and is sorta hacky. It is also not very efficient, but it does the job.
The second one needs to know the number of decimals and uses simple multiplication. NOTE: This method will not do any kind of checking on whether the float you pass in actually has that number of decimals.
None of these methods are particularly elegant, but they worked well for the numbers I tested ( both positive and negative. ) Feel free to comment if you find bugs/errors or if you have suggestions for improvement.
EDIT : As #dan04 pointed out, this method will return the same value for 0.4 as for 0.04. If you want do distinguish these, you'd need a second int for storing the number of zeros after the decimal point.
#include <iostream>
#include <sstream>
#include <math.h>
int GetDecimalsUsingString( float number );
int GetDecimals( float number, int num_decimals );
int main() {
float x = 1234.5678;
int x1 = (int) x; // which would return 1234 great.
float remainder = x - static_cast< float > ( x1 );
std::cout << "Original : " << x << std::endl;
std::cout << "Before comma : " << x1 << std::endl;
std::cout << "Remainder : " << remainder << std::endl;
// "Ugly" way using std::stringstream and std::string
int res_string = GetDecimalsUsingString( remainder );
// Nicer, but requires that you specify number of decimals
int res_num_decimals = GetDecimals( remainder, 5 );
std::cout << "Result using string : " << res_string << std::endl;
std::cout << "Result using known number of decimals : " << res_num_decimals << std::endl;
return 0;
}
int GetDecimalsUsingString( float number )
{
// Put number in a stringstream
std::stringstream ss;
ss << number;
// Put content of stringstream into a string
std::string str = ss.str();
// Remove the first part of the string ( minus symbol, 0 and decimal point)
if ( number < 0.0 )
str = str.substr( 3, str.length() - 1);
else
str = str.substr( 2, str.length() - 1);
// Convert string back to int
int ret = std::strtol( str.c_str(), NULL, 10 );
/// Preserve sign
if ( number < 0 )
ret *= -1;
return ret;
}
int GetDecimals( float number, int num_decimals )
{
int decimal_multiplier = pow( 10, num_decimals );
int result = number * decimal_multiplier;
return result;
}
Output :
Original : 1234.57
Before comma : 1234
Remainder : 0.567749
Result using string : 567749
Result using known number of decimals : 56774
Ideone

I guess there are no built in C/C++ commands to do this, other than the 2 methods of:
1) Using the above to convert into string and then scan back into 2 ints.
2) Accessing the memory contents of the memory variable and then decoding manually.

Related

Double precision issues when converting it to a large integer

Precision is the number of digits in a number. Scale is the number of
digits to the right of the decimal point in a number. For example, the
number 123.45 has a precision of 5 and a scale of 2.
I need to convert a double with a maximum scale of 7(i.e. it may have 7 digits after the decimal point) to a __int128. However, given a number, I don't know in advance, the actual scale the number has.
#include <iostream>
#include "json.hpp"
using json = nlohmann::json;
#include <string>
static std::ostream& operator<<(std::ostream& o, const __int128& x) {
if (x == std::numeric_limits<__int128>::min()) return o << "-170141183460469231731687303715884105728";
if (x < 0) return o << "-" << -x;
if (x < 10) return o << (char)(x + '0');
return o << x / 10 << (char)(x % 10 + '0');
}
int main()
{
std::string str = R"({"time": [0.143]})";
std::cout << "input: " << str << std::endl;
json j = json::parse(str);
std::cout << "output: " << j.dump(4) << std::endl;
double d = j["time"][0].get<double>();
__int128_t d_128_bad = d * 10000000;
__int128_t d_128_good = __int128(d * 1000) * 10000;
std::cout << std::setprecision(16) << std::defaultfloat << d << std::endl;
std::cout << "d_128_bad: " << d_128_bad << std::endl;
std::cout << "d_128_good: " << d_128_good << std::endl;
}
Output:
input: {"time": [0.143]}
output: {
"time": [
0.143
]
}
0.143
d_128_bad: 1429999
d_128_good: 1430000
As you can see, the converted double is not the expected 1430000 instead it is 1429999. I know the reason is that a float point number can not be represented exactly. The problem can be solved if I know the number of digit after the decimal point.
For example,
I can instead use __int128_t(d * 1000) * 10000. However, I don't know the scale of a given number which might have a maximum of scale 7.
Question> Is there a possible solution for this? Also, I need to do this conversion very fast.
I'm not familiar with this library, but it does appear to have a mechanism to get a json object's string representation (dump()). I would suggest you parse that into your value rather than going through the double intermediate representation, as in that case you will know the scale of the value as it was written.

how to handle floating point imprecision? [duplicate]

This question already has answers here:
Why does floating-point arithmetic not give exact results when adding decimal fractions?
(31 answers)
Closed 2 years ago.
I am converting an array of bytes to a 32 bit floating point. Sometimes the numbers are slightly off.
Example:
10.1 becomes 10.100000381469727 when I serialize the value in RapidJSON. How can I normalize this?
I can't share that code. What I can share is this to prove it:
std::string BytesToHexString(
unsigned char* data,
size_t len
)
{
std::stringstream ss;
ss << std::hex << std::setfill('0');
for (size_t i = len - 1; i >= 0 && i < len; --i)
ss << std::setw(2) << static_cast<int>(data[i]);
return ss.str();
}
std::string FLOATvalueToHexString(
float value
)
{
union FloatToUChar {
float f;
unsigned char c[sizeof(float)];
};
FloatToUChar floatUnion;
floatUnion.f = value;
return BytesToHexString(
floatUnion.c,
sizeof(float)
);
}
int main()
{
std::string sFloatValue = "10.100000";
float fltValue = atof(sFloatValue.c_str());
std::string strHexFloatValue = FLOATvalueToHexString(fltValue);
std::cout << sFloatValue << " " << fltValue << " " << strHexFloatValue << std::endl;
return 0;
}
It prints: 10.100000 10.1 4121999a
The debugger says fltValue is 10.1000004.
If I convert 4121999a then this confirms that the internal storage is indeed off:
https://babbage.cs.qc.cuny.edu/IEEE-754.old/32bit.html
10.100000381469727
How can I normalize the floating point so I can at least get the correct hexadecimal value?
Just like an int type can't be used to non-whole numbers, a double can only store a subset of the real numbers too.
If you want to be able to store 0.1 exactly, then use a decimal type. See C++ decimal data types for a starting point.
Job done!

What does double store?

I'm sending the value 4 *cos( fmod( acos(2.0/4.0), 2*3.14159265) ) as double to this function but I get output as
2
1k1
What is wrong here?
void convert_d_to_f(double n)
{
cout<<n<<" ";
double mantissa;
double fractional_part;
fractional_part = modf(n,&mantissa);
double x = fractional_part;
cout<<mantissa<<"k"<<fractional_part<<'\n';
}
The problem is that cout truncates and rounds double while printing. You can print the desired number of decimal places usingiomanip library.
#include <iostream>
#include <cmath>
#include <iomanip>
void convert_d_to_f(double n)
{
cout<<std::fixed<<std::setprecision(20); //number of decimal places you need to print to
cout<<n<<" ";
double mantissa;
double fractional_part;
fractional_part = modf(n,&mantissa);
double x = fractional_part;
cout<<mantissa<<"k"<<fractional_part<<'\n';
}
int main() {
convert_d_to_f(4 *cos( fmod( acos(2.0/4.0), 2*3.14159265) ));
return 0;
}
For all practical intents and purposes, your number n evaluates to 2. If you want it to display as 1.9999999... etc. then follow Kapil's solution and set the floating point precision for std::cout to many decimal places. Keep in mind the difference between precision and accuracy if you are going to go that route.
That being said, your void convert_d_to_f(double n) function is replicating the functionality of std::frexp(double arg, int* exp) with a limitation where your results are going out of scope after you print them to the screen. If you desire to use your exponent and mantissa values after computing them, then you can do it like this.
#include <iostream>
#include <cmath>
int main()
{
double n = 4 *cos( fmod( acos(2.0/4.0), 2*3.14159265) );
std::cout << "Given the number " << n << std::endl;
// convert the given floating point value `n` into a
// normalized fraction and an integral power of two
int exp;
double mantissa = std::frexp(n, &exp);
// display results as Mantissa x 2^Exponent
std::cout << "We have " << n << " = "
<< mantissa << " * 2^" << exp << std::endl;
return 0;
}

separating decimal points into two integers

I have been given double x = 23.456; and two integer d and c.
I have to break it so that d gets the value 23 and c gets the value 456.
I thought of the following:-
int d;
d=(int)x;
but I cannot think of what to do with c as it is an integer and if i write
c=(x-d)*1000;
then it might be applicable for this case only and not for any other case.
Is there any way to get the number of digits after the decimal and then multiply it with equal number of zeros.
Please help!!!
You could repeatedly multiply it by 10, until there is nothing after decimal point.
double c = x - d;
while(c - floor(c) > 0.0)
{c *= 10;}
you may also need to #include <math.h> for floor function, which rounds down a number. e.g. floor(4.9) returns 4.0
Floating point calculations are little bit tricky in C++ (same is true for Java and other languages). You should avoid their direct comparison and do some other stuff to get predictable result when using them, consider:
double d1=1.1;
double d2= d1 / 10.0;
if(d2==0.11)cout << "equals" << endl;
else cout << "not equals" << endl; //result is "not equals"
d1=1.99;
float f1=0.01f;
double d3=d1+f1;
if(d3==2.0)cout << "equals" << endl;
else cout << "not equals" << endl; //result is "not equals"
d1=1.99;
d2=0.01;
d3=d1+d2-2.0;
if(d3==0.0)cout << "equals" << endl;
else cout << "not equals" << endl; //result is "not equals"
As for practical solution of the problem I can suggest 2 variants:
Var 1 is to use a function that allows to specify number of digits:
#include <iostream>
#include <cmath>
using namespace std;
void split_double(const double value, int& i_part, int& r_part,
const int max_digits_after_dp, int min_digits_after_dp){
auto powerOfTenL = [](int power){ int result = 1;
for(int i=0;i<power;++i)result *= 10;
return result;
};
//Get integral part
i_part = (int)value;
double temp = (value-i_part);
double pOfTen = powerOfTenL(max_digits_after_dp);
temp *= pOfTen;
//Get real part
r_part = round(temp);
//Remove zeroes at the right in real part
int num_of_d = max_digits_after_dp;
if(min_digits_after_dp>max_digits_after_dp)
min_digits_after_dp=max_digits_after_dp;
while (num_of_d>min_digits_after_dp) {
//If the number is divisible by 10, divide it by 10
if(0==(r_part%10)) { r_part /=10; num_of_d--;
}
else break; //Last digit is not 0
}
}
int main(int argc, char *argv[])
{
double value = 10.120019;
int ipart,rpart;
const int digitsMax = 6;
const int digitsMin = 3;
split_double(value,ipart,rpart,digitsMax,digitsMin);
cout<<"Double " <<value << " has integral part " <<ipart
<<" and real part "<<rpart<<endl;
return 0;
}
Second variant to solve the problem is to use C/C++ formatting functions like vsprintf and then split the resulting string.

precision of double function based string

Let's say that you have a function:
string function(){
double f = 2.48452
double g = 2
double h = 5482.48552
double i = -78.00
double j = 2.10
return x; // ***
}
* for x we insert:
if we will insert f, function returns: 2.48
if we will insert g, function returns: 2
if we will insert h, function returns: 5482.49
if we will insert i, function returns:-78
if we will insert j, function returns: 2.1
They are only example, who shows how the funcion() works. To precise:
The function for double k return rounded it to: k.XX,
but for:
k=2.20
it return 2.2 as string.
How it implements?
1) Just because you see two digits, it doesn't mean the underlying value was necessarily rounded to two digits.
The precision of the VALUE and the number of digits displayed in the FORMATTED OUTPUT are two completely different things.
2) If you're using cout, you can control formatting with "setprecision()":
http://www.cplusplus.com/reference/iomanip/setprecision/
EXAMPLE (from the above link):
// setprecision example
#include <iostream> // std::cout, std::fixed
#include <iomanip> // std::setprecision
int main () {
double f =3.14159;
std::cout << std::setprecision(5) << f << '\n';
std::cout << std::setprecision(9) << f << '\n';
std::cout << std::fixed;
std::cout << std::setprecision(5) << f << '\n';
std::cout << std::setprecision(9) << f << '\n';
return 0;
}
sample output:
3.1416
3.14159
3.14159
3.141590000
Mathematically, 2.2 is exactly the same as 2.20, 2.200, 2.2000, and so on. If you want to see more insignificant zeros, use [setprecision][1]:
cout << fixed << setprecision(2);
cout << 2.2 << endl; // Prints 2.20
To show up to 2 decimal places, but not showing trailing zeros you can do something such as:
std::string function(double value)
{
// get fractional part
double fracpart = value - static_cast<long>(value);
// compute fractional part rounded to 2 decimal places as an int
int decimal = static_cast<int>(100*fabs(fracpart) + 0.5);
if (decimal >= 100) decimal -= 100;
// adjust precision based on the number of trailing zeros
int precision = 2; // default 2 digits precision
if (0 == decimal) precision = 0; // 2 trailing zeros, don't show decimals
else if (0 == (decimal % 10)) precision = 1; // 1 trailing zero, keep 1 decimal place
// convert value to string
std::stringstream str;
str << std::fixed << std::setprecision(precision) << value;
return str.str();
}