Problem with multiplying 2 numbers in truncation procedure - c++

I need truncation of 2 decimal digits after decimal comma.
I am using following code in C++:
auto doubleTmp = value * 100.00;
int64_t tmp = static_cast<int64_t>(doubleTmp);
double res = ( static_cast<double>(tmp) ) /100.00;
but for example when I set value = 70.82 doubleTmp is 70.8199999 and result is 70.81. What will better way for this and why?

The problem is that neither the input value nor the result res is representable in a computer memory accurately for 70.82. As #MatthieuBrucher suggested, you should use std::lround; consider the following code:
auto value = 70.82;
std::cout << std::fixed << std::setprecision(20) << value << std::endl;
auto tmp = std::lround(value * 100.0);
std::cout << tmp << std::endl;
double res = static_cast<double>(tmp) / 100.00;
std::cout << std::fixed << std::setprecision(20) << res << std::endl;
Which gives the following output:
70.81999999999999317879
7082
70.81999999999999317879
However, you can store the result as a pair of integral numbers, where the first one will represent the integral part and the second one the fractional part:
auto res_integral = tmp / 100;
auto res_fractional = tmp % 100;
std::cout << res_integral << "." << res_fractional << std::endl;
Or, simply store it as tmp with the knowledge that you are storing 100*x instead of x.

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.

std::setprecision sets the number of significant figures. How do I use iomanip to set the precision?

I have always found iomanip confusing and counter intuitive. I need help.
A quick internet search finds (https://www.vedantu.com/maths/precision) "We thus consider precision as the maximum number of significant digits after the decimal point in a decimal number" (the emphasis is mine). That matches my understanding too. However I wrote a test program and:
stm << std::setprecision(3) << 5.12345678;
std::cout << "5.12345678: " << stm.str() << std::endl;
stm.str("");
stm << std::setprecision(3) << 25.12345678;
std::cout << "25.12345678: " << stm.str() << std::endl;
stm.str("");
stm << std::setprecision(3) << 5.1;
std::cout << "5.1: " << stm.str() << std::endl;
stm.str("");
outputs:
5.12345678: 5.12
25.12345678: 25.1
5.1: 5.1
If the precision is 3 then the output should be:
5.12345678: 5.123
25.12345678: 25.123
5.1: 5.1
Clearly the C++ standard has a different interpretation of the meaning of "precision" as relates to floating point numbers.
If I do:
stm.setf(std::ios::fixed, std::ios::floatfield);
then the first two values are formatted correctly, but the last comes out as 5.100.
How do I set the precision without padding?
You can try using this workaround:
decltype(std::setprecision(1)) setp(double number, int p) {
int e = static_cast<int>(std::abs(number));
e = e != 0? static_cast<int>(std::log10(e)) + 1 + p : p;
while(number != 0.0 && static_cast<int>(number*=10) == 0 && e > 1)
e--; // for numbers like 0.001: those zeros are not treated as digits by setprecision.
return std::setprecision(e);
}
And then:
auto v = 5.12345678;
stm << setp(v, 3) << v;
Another more verbose and elegant solution is to create a struct like this:
struct __setp {
double number;
bool fixed = false;
int prec;
};
std::ostream& operator<<(std::ostream& os, const __setp& obj)
{
if(obj.fixed)
os << std::fixed;
else os << std::defaultfloat;
os.precision(obj.prec);
os << obj.number; // comment this if you do not want to print immediately the number
return os;
}
__setp setp(double number, int p) {
__setp setter;
setter.number = number;
int e = static_cast<int>(std::abs(number));
e = e != 0? static_cast<int>(std::log10(e)) + 1 + p : p;
while(number != 0.0 && static_cast<int>(number*=10) == 0)
e--; // for numbers like 0.001: those zeros are not treated as digits by setprecision.
if(e <= 0) {
setter.fixed = true;
setter.prec = 1;
} else
setter.prec = e;
return setter;
}
Using it like this:
auto v = 5.12345678;
stm << setp(v, 3);
I don't think you can do it nicely. There are two candidate formats: defaultfloat and fixed. For the former, "precision" is the maximum number of digits, where both sides of the decimal separator count. For the latter "precision" is the exact number of digits after the decimal separator.
So your solution, I think, is to use fixed format and then manually clear trailing zeros:
#include <iostream>
#include <iomanip>
#include <sstream>
void print(const double number)
{
std::ostringstream stream;
stream << std::fixed << std::setprecision(3) << number;
auto string=stream.str();
while(string.back()=='0')
string.pop_back();
if(string.back()=='.') // in case number is integral; beware of localization issues
string.pop_back();
std::cout << string << "\n";
}
int main()
{
print(5.12345678);
print(25.12345678);
print(5.1);
}
The fixed format gives almost what you want except that it preserves trailing zeros. There is no built-in way to avoid that but you can easily remove those zeros manually. For example, in C++20 you can do the following using std::format:
std::string format_fixed(double d) {
auto s = fmt::format("{:.3f}", d);
auto end = s.find_last_not_of('0');
return end != std::string::npos ? std::string(s.c_str(), end + 1) : s;
}
std::cout << "5.12345678: " << format_fixed(5.12345678) << "\n";
std::cout << "25.12345678: " << format_fixed(25.12345678) << "\n";
std::cout << "5.1: " << format_fixed(5.1) << "\n";
Output:
5.12345678: 5.123
25.12345678: 25.123
5.1: 5.1
The same example with the {fmt} library, std::format is based on: godbolt.
Disclaimer: I'm the author of {fmt} and C++20 std::format.

How to display C++ Boost Library multi-precision big integers in binary form?

I'm new to Boost and trying to use its multi-precision library to multiply very large inputs:
mp::uint1024_t my_1024_bit_int1 = 0b00100101101000100010010...010101;
mp::uint1024_t my_1024_bit_int2 = 0b0010101001000101000010100000001001...01010111; // bigger in practice
mp::uint1024_t my_1024_bit_result = my_1024_bit_int2*my_1024_bit_int1;
I need to be able to save the result as a string in binary form. I have tried to access the number of "limbs" in the integer:
int limbs = my_1024_bit_result.backend.limbs();
and then iterate through each limb and use the bitset function to convert each limb to a binary string, but it did not work.
How else could I achieve this?
If you actually meant binary digits:
template <typename Integer>
std::string to_bin(Integer num) {
auto sign = num.sign();
num = abs(num);
std::string result;
while (num) {
result += "01"[int(num % 2)];
num /= 2;
}
result += sign<0? "b0-": "b0";
std::reverse(begin(result), end(result));
return result;
}
Note how it supports signed types as well
Live On Coliru
int main() {
mp::uint1024_t a=0b00100101101000100010010010101;
mp::uint1024_t b=0b001010100100010100001010000000100101010111; // bigger in practice
mp::uint1024_t c = a * b;
std::cout << a << " * " << b << " = " << c << "\n";
std::cout << "\n" << to_bin(a) << " * " << to_bin(b) << "\n = " << to_bin(c) << "\n";
}
Prints
78922901 * 726187641175 = 57312835311878048675
0b100101101000100010010010101 * 0b1010100100010100001010000000100101010111
= 0b110001101101100000000110000000111101001010111101001000101110100011
Serialization?
In case you meant "binary serialization", use serialization:
Writing boost::multiprecision data type to binary file

Remove numbers after decimal point in c++ (without floor() function)

How would i replicate the code below but without using the floor() function? I need to do this because i'm in a postion that i cannot use the floor() function
double quickExampleee = 3.1459038585;
std::cout << std::floor(quickExamplee * 100.) / 100. << std::endl;
I've searched for answers all around and haven't been able to find anything? Anyways thanks for your time,
What about using std::setprecision if you don't like to cast the numbers to int's, like
std::cout << std::setprecision(0) << quickExamplee << std::endl;
so to print out 3.14 you simply set precision to 2, like
std::cout << std::setprecision(2) << quickExamplee << std::endl;
You could do static_cast<int>(quickExampleee * 100.) as long as the double is greater than 0.
int myFloorForWhateverReason(double x) {
if (x > 0.0)
return (int)x;
else
return (int)(x - 0.5);
}
double quickExampleee = 3.1459038585;
std::cout << myFloorForWhateverReason(quickExamplee * 100.) / 100. << std::endl;

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();
}