I want to convert a MPFR floating point number into a string.
If I run my program the string is generated but without the "." in the number. How can I do it right?
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <mpreal.h>
using mpfr::mpreal;
using std::cout;
using std::endl;
int main (int ac, char *av[])
{
char data[255];
mpreal x = 42.0, y = 3.14159265358979323846, res = 0.0;
mp_exp_t exponent = 10;
// string data_str[256];
int precision = 50;
res = x * y;
cout.precision(100);
cout << res;
cout << "\n";
// if (mpfr_snprintf (data, 254, "%.20Ff", res.mpfr_srcptr()) < 0)
/*
if (mpfr_snprintf (data, 254, "%.20Ff", res.mpfr_srcptr()) < 0)
{
cout << "gmp_prints_float: error saving string!\n";
}
*/
mpfr_get_str ((char *) &data, &exponent, 10, precision, res.mpfr_srcptr(), GMP_RNDN);
cout << data;
cout << "\n";
mpfr_free_cache ();
}
131.946891450771317977341823279857635498046875
13194689145077131797734182327985763549804687500000
There is no decimal point in the string output!
From the documentation
The generated string is a fraction, with an implicit radix point immediately to the left of the first digit. For example, the number -3.1416 would be returned as "-31416" in the string and 1 written at expptr.
It is up to you to generate a human-readable representation fron the string and the exponent.
An alternative would be to use mpfr_sprintf.
MPFR's mpfr_get_str function is copied on GMP's mpf_get_str function, explaining why it has been chosen not to write a decimal point. There are two solutions to have a decimal point:
Use mpfr_sprintf (or some variant), as suggested in this answer. I would recommend this solution (perhaps unless you want to ignore the locales), as it is the most flexible in the output format and does not need a correction.
If you just want the significand with an explicit decimal point, use mpfr_get_str, but with a pointer buffer+1 instead of buffer. Then, do something like (disregarding the locales)
int neg = buffer[1] == '-';
if (neg)
buffer[0] = '-';
buffer[neg] = '.';
after filtering the special cases (NaN and infinities).
Related
The cppreference documentation states that std::round will specifically round away from zero in "halfway cases." While this is true with the literal 0.5, it's not true with std::sin(pi/6). I thought this might be a floating point error, so I printed the value but it's exactly 0.5. After inspecting the binary representation however, I can see that they are indeed represented differently. I've provided the code I used to make these inspections below.
#include <iostream>
#include <stdio.h>
#include <cmath>
int main(int argc, char * argv[])
{
double const pi = std::acos(-1);
double const a = std::sin(pi/6);
double const b = 0.5;
std::cout << "round(" << a << ") = " << std::round(a) << "\n";
auto pa = reinterpret_cast<const unsigned char *>(&a);
auto pb = reinterpret_cast<const unsigned char *>(&b);
std::cout << "a = 0x";
for (size_t i = 0; i != sizeof(double); ++i) {
printf("%02x", pa[i]);
}
std::cout << "\nb = 0x";
for (size_t i = 0; i != sizeof(double); ++i) {
printf("%02x", pb[i]);
}
std::cout << "\n";
}
round(0.5) = 0
round(0.5) = 1
a = 0xffffffffffffdf3f
b = 0x000000000000e03f
So my question is this rounding behavior a part of the c++ specification or is this a bug? And in any case, is there some general way that I can "correct" the representation of the value returned by sin? I'm not sure what format it's in because based off what I know of IEEE-754, it looks like it should be NaN. Although from what I understand, c++ doesn't guarantee IEEE-754 floating point representation?
The issue is that you're not printing the value with enough significant digits. When I increase precision with std::setprecision(20), I get: round(0.49999999999999994449) = 0.
You can see this for yourself by either changing the code or entering 3fdfffffffffffff into the bottom Hexadecimal field of this online calculator: https://baseconvert.com/ieee-754-floating-point
The representation looks like NaN because you're reading it backwards. x86/x64 have little-endian floating point numbers. So you should read that it from high to low address, yielding 0x3fdfffff..., which is of course slightly less than 0.5.
I want to ask how to remove trailing zeros after decimal point?
I've read lots of topics about it but I don't understand them clearly. Could you show me any easy understanding ways ?
For example 12.50 to 12.5, but the actual output is 12.50
This is one thing that IMHO is overly complicated in C++. Anyway, you need to specify the desired format by setting properties on the output stream. For convenience a number of manipulators are defined.
In this case, you need to set fixed representation and set precision to 2 to obtain the rounding to 2 decimals after the point using the corresponding manipulators, see below (notice that setprecisioncauses rounding to the desired precision). The tricky part is then to remove trailing zeroes. As far as I know C++ does not support this out of the box, so you have to do some string manipulation.
To be able to do this, we will first "print" the value to a string and then manipulate that string before printing it:
#include <iostream>
#include <iomanip>
int main()
{
double value = 12.498;
// Print value to a string
std::stringstream ss;
ss << std::fixed << std::setprecision(2) << value;
std::string str = ss.str();
// Ensure that there is a decimal point somewhere (there should be)
if(str.find('.') != std::string::npos)
{
// Remove trailing zeroes
str = str.substr(0, str.find_last_not_of('0')+1);
// If the decimal point is now the last character, remove that as well
if(str.find('.') == str.size()-1)
{
str = str.substr(0, str.size()-1);
}
}
std::cout << str << std::endl;
}
For C++ check this How to output float to cout without scientific notation or trailing zeros?
using printf() you may use following method to do this,
int main()
{
double value = 12.500;
printf("%.6g", value ); // 12.5 with 6 digit precision
printf("%.6g", 32.1234); // 32.1234
printf("%.6g", 32.12300000); // 32.123
}
std::string example = std::to_string(10.500f);
while (example[example.size() - 1] == '0' || example[example.size() - 1] == '.')
example.resize(example.size() - 1);
Just use 'printf' function.
printf("%.8g",8.230400); will print '8.2304'
float value =4.5300;
printf ("%.8g",value);
will return 4.53.
Try this code . It is quite simple.
I was stumped by this for a while and didn't want to convert to a string to get the job done, so I came up with this:
float value = 1.00;
char buffer[10];
sprintf(buffer, "%.2f", value);
int lastZero = strlen(buffer);
for (int i = strlen(buffer) - 1; i >= 0; i--)
{
if (buffer[i] == '\0' || buffer[i]=='0' || buffer[i]=='.')
lastZero = i;
else
break;
}
if (lastZero==0)
lastZero++;
char newValue[lastZero + 1];
strncpy(newValue, buffer, lastZero);
newValue[lastZero] = '\0';
newValue = 1
you can round-off the value to 2 digits after decimal,
x = floor((x * 100) + 0.5)/100;
and then print using printf to truncate any trailing zeros..
printf("%g", x);
example:
double x = 25.528;
x = floor((x * 100) + 0.5)/100;
printf("%g", x);
output: 25.53
It's C++ code written in Visual Studio 2015. It's something as below,
LPSTR *endPtr;
string strDouble = "0.03456";
double valDouble = strtod(strDouble.c_str(), &endPtr);
Now the output in valDouble is "0.0345555566", something like that.
I want the value in valDouble to be exactly "0.03456".
Basically the value of "0.0345555566" needs to be rounded to say "0.03456".
Is there a way it can be achieved?
BTW, the value in strDouble changes all the time. So it's not possible to set precision to say 5 or something like that. Below are few examples that goes in to strDouble.
string strDouble = "0.1889";
string strDouble = "0.00883342";
string strDouble = "0.2111907";
string strDouble = "3.0045";
string strDouble = "1.45";
I want the value in valDouble to be exactly "0.03456".
That's not possible, unless you target a system whose double floating point representation can represent that number.
There exists no representation for 0.03456 in the ubiquitous IEEE 754 binary64 standard which your CPU probably uses. The closest representable number is 3.45600000000000004418687638008E-2. That's the number that you should get whether you use strtod, stod or a character stream to convert the string.
Is there a way it can be achieved?
In order to represent 0.03456 exactly on a system whose floating point cannot represent that number, you must use integers to represent the number. You can implement arbitrary precision arithmetic, fixed-point arithmetic or a decimal floating point using integers.
Basically the value ... needs to be rounded to say "0.03456".
You can round the output when you convert the non-exact float into a string:
std::cout << std::setprecision(4) << 0.03456;
BTW, the value in strDouble changes all the time. So it's not possible to set precision to say 5 or something like that.
Then you have to record the number of significant digits in the input string in order to use the same precision in output.
Here's an example function for that purpose:
template<class Range>
auto get_precision(const Range& r)
{
auto is_significant = [](auto c) {
return std::isdigit(c) && c != '0';
};
auto first = std::find_if(std:: begin(r), std:: end(r), is_significant);
auto last = std::find_if(std::rbegin(r), std::rend(r), is_significant).base();
return std::count_if(first, last, [](auto c) {
return std::isdigit(c);
});
}
// demo
std::cout << get_precision("0.03456"); // 4
Assuming that you want the number of digits after decimal point as some percent of the total number of digits after the decimal, you could do something like,
Calculate the number of digits after decimal point. Let it be n
Now convert the string to decimal just like you are doing. Let this be d
Now if you want 50% of the decimal places to be retained, you could do use an old trick,
double d_new = round(d * pow(10.0, 5)) / pow(10.0, 5). Assuming precision till 5 digits.
Note: Unlike the other answers, here you are rounding the original decimal itself. Not just printing the rounded decimal to stdout.
Example:
#include<stdio.h>
#include<cmath>
int main(){
double a = 0.0345555566;
double b = 0.00883342;
double c = 0.2111907;
double a_new = round(a * pow(10.0, 5)) / pow(10.0, 5);
double b_new = round(b * pow(10.0, 4)) / pow(10.0, 4);
double c_new = round(c * pow(10.0, 3)) / pow(10.0, 3);
printf("%.10f\n", a_new);
printf("%.10f\n", b_new);
printf("%.10f\n", c_new);
}
See the 50% precision
Results:
0.0345600000
0.0088000000
0.2110000000
Use string stream instead of strtod:
#include <iostream>
#include <sstream>
double convert(std::string string) {
std::stringstream s(string);
double ret = 0;
s >> ret;
return ret;
}
int main() {
std::cerr << convert("0.03456") << std::endl;
std::cerr << convert("0.1889") << std::endl;
std::cerr << convert("0.00883342") << std::endl;
std::cerr << convert("0.2111907") << std::endl;
std::cerr << convert("3.0045") << std::endl;
std::cerr << convert("1.45") << std::endl;
return 0;
}
On my system, this gives:
0.03456
0.1889
0.00883342
0.211191
3.0045
1.45
As some have pointed out in the comments, not all numbers can be represented with doubles. But most of the ones you listed can be.
I need to use an existing text file to store some very precise values. When read back in, the numbers essentially need to be exactly equivalent to the ones that were originally written. Now, a normal person would use a binary file... for a number of reasons, that's not possible in this case.
So... do any of you have a good way of encoding a double as a string of characters (aside from increasing the precision). My first thought was to cast the double to a char[] and write out the chars. I don't think that's going to work because some of the characters are not visible, produce sounds, and even terminate strings ('\0'... I'm talkin to you!)
Thoughts?
[Edit] - once I figure out which of the solutions proposed works best for me, I'll mark one as 'the' solution.
If you want to keep the format strictly human readable, you can write out the double thusly:
#include <iomanip>
#include <sstream>
std::string doubleToText(const double & d)
{
std::stringstream ss;
//ss << std::setprecision( std::numeric_limits<double>::digits10+2);
ss << std::setprecision( std::numeric_limits<int>::max() );
ss << d;
return ss.str();
}
std::numeric_limits<int>::max() will output with the maximum possible decimal precision. This will preserve the value most precisely across differently floating point implementations. Swapping that line for the commented line using std::numeric_limits<double>::digits10+2 will give just enough precision to make the double precisely recoverable on the platform the code is compiled for. This gives a much shorter output and preserves as much information as the double can uniquely represent.
The C++ stream operators do not preserve denormalized numbers or the infinities and not-a-numbers when reading strings in. However, the POSIX strtod function does, and is defined to by the standard. Hence, the most precise way to read a decimal number back with a standard library call would be this function:
#include <stdlib.h>
double textToDouble(const std::string & str)
{
return strtod( str.c_str(), NULL );
}
Assuming IEEE 754 double, printf("%.17g\n", x) will give you enough digits to recreate the original value.
A two step process: First use binary float/double serialization and then apply base 64 encoding. The result is not human readable, but will not loose precision.
Edit: (Thanks to fuzzyTew and dan04)
Lossless decimal and human readable representation is probably possible, but would require much more space.
You could use base 64. This would allow you to store the exact byte values in a text file.
I haven't used it, but I found this base 64 encoding/decoding library for C++.
To print long lists of numbers in C++ without loss (write and read in the same arquitecture) I use this (for doubles):
#include<iostream>
#include<iomanip>
#include<limits>
#include<cmath>
#include<sstream>
int main(){
std::ostringstream oss;
int prec = std::numeric_limits<double>::digits10+2; // generally 17
int exponent_digits = std::log10(std::numeric_limits<double>::max_exponent10)+1; // generally 3
int exponent_sign = 1; // 1.e-123
int exponent_symbol = 1; // 'e' 'E'
int digits_sign = 1;
int digits_dot = 1; // 1.2
int division_extra_space = 1;
int width = prec + exponent_digits + digits_sign + exponent_sign + digits_dot + exponent_symbol + division_extra_space;
double original = -0.000013213213e-100/33215.;
oss << std::setprecision(prec) << std::setw(width) << original << std::setw(width) << original << std::setw(width) << original << '\n';
oss << std::setprecision(prec) << std::setw(width) << 1. << std::setw(width) << 2. << std::setw(width) << -3. << '\n';
}
prints
-3.9780861056751466e-110 -3.9780861056751466e-110 -3.9780861056751466e-110
1 2 -3
In summary, in my case it is like setting:
oss << std::precision(17) << std::setw(25) << original << ...;
In any case I can test if this works, by doing:
std::istringstream iss(oss.str());
double test; iss >> test;
assert(test == original);
I was sure there was a special format specifier for printf (maybe %a?) that allowed printing the binary representation of a float, but I cannot find it..
However, you can try this:
int main(int argc, char* argv[]){
union fi {
unsigned int i;
float f;
} num;
num.f = 1.23f;
printf("%X\n", num.i);
return 0;
}
Try this:
double d = 0.2512958125912;
std::ostringstream s;
s << d;
Then write s to file.
You don't say why binary is off limits. For your application would conqverting the binary to a hex ASCII string be workable?
Storage representation aside, what about something like this.
Special values like -0, infinities, NaN etc would require special
handling though. Also I "forgot" to implement negative exponents.
#include <stdio.h>
#include <math.h>
const int SCALE = 1<<(52/2);
void put( double a ) {
FILE* f = fopen( "dump.txt", "wb" );
int sign = (a<0); if( sign ) a=-a;
int exp2 = 0; while( a>1 ) a/=2, exp2++;
a*=SCALE;
int m1 = floor(a);
a = (a-m1)*SCALE;
int m2 = floor(a);
fprintf(f, "%i %i %i %i\n", sign, exp2, m1, m2 );
fclose(f);
}
double get( void ) {
FILE* f = fopen( "dump.txt", "rb" );
double a;
int sign, exp2, m1, m2;
fscanf( f, "%i %i %i %i\n", &sign, &exp2, &m1, &m2 );
fclose(f);
printf( "%i %i %i %i\n", sign, exp2, m1, m2 );
a = m2; a /= SCALE;
a+= m1; a /= SCALE;
while( exp2>0 ) a*=2, exp2--;
if( a<0 ) a=-a;
return a;
}
int main( void ) {
union {
double a;
unsigned b[2];
};
a = 3.1415926;
printf( "%.20lf %08X %08X\n", a, b[0], b[1] );
put( a );
a = get();
printf( "%.20lf %08X %08X\n", a, b[0], b[1] );
}
I have an int that I want to store as a binary string representation. How can this be done?
Try this:
#include <bitset>
#include <iostream>
int main()
{
std::bitset<32> x(23456);
std::cout << x << "\n";
// If you don't want a variable just create a temporary.
std::cout << std::bitset<32>(23456) << "\n";
}
I have an int that I want to first convert to a binary number.
What exactly does that mean? There is no type "binary number". Well, an int is already represented in binary form internally unless you're using a very strange computer, but that's an implementation detail -- conceptually, it is just an integral number.
Each time you print a number to the screen, it must be converted to a string of characters. It just so happens that most I/O systems chose a decimal representation for this process so that humans have an easier time. But there is nothing inherently decimal about int.
Anyway, to generate a base b representation of an integral number x, simply follow this algorithm:
initialize s with the empty string
m = x % b
x = x / b
Convert m into a digit, d.
Append d on s.
If x is not zero, goto step 2.
Reverse s
Step 4 is easy if b <= 10 and your computer uses a character encoding where the digits 0-9 are contiguous, because then it's simply d = '0' + m. Otherwise, you need a lookup table.
Steps 5 and 7 can be simplified to append d on the left of s if you know ahead of time how much space you will need and start from the right end in the string.
In the case of b == 2 (e.g. binary representation), step 2 can be simplified to m = x & 1, and step 3 can be simplified to x = x >> 1.
Solution with reverse:
#include <string>
#include <algorithm>
std::string binary(unsigned x)
{
std::string s;
do
{
s.push_back('0' + (x & 1));
} while (x >>= 1);
std::reverse(s.begin(), s.end());
return s;
}
Solution without reverse:
#include <string>
std::string binary(unsigned x)
{
// Warning: this breaks for numbers with more than 64 bits
char buffer[64];
char* p = buffer + 64;
do
{
*--p = '0' + (x & 1);
} while (x >>= 1);
return std::string(p, buffer + 64);
}
AND the number with 100000..., then 010000..., 0010000..., etc. Each time, if the result is 0, put a '0' in a char array, otherwise put a '1'.
int numberOfBits = sizeof(int) * 8;
char binary[numberOfBits + 1];
int decimal = 29;
for(int i = 0; i < numberOfBits; ++i) {
if ((decimal & (0x80000000 >> i)) == 0) {
binary[i] = '0';
} else {
binary[i] = '1';
}
}
binary[numberOfBits] = '\0';
string binaryString(binary);
http://www.phanderson.com/printer/bin_disp.html is a good example.
The basic principle of a simple approach:
Loop until the # is 0
& (bitwise and) the # with 1. Print the result (1 or 0) to the end of string buffer.
Shift the # by 1 bit using >>=.
Repeat loop
Print reversed string buffer
To avoid reversing the string or needing to limit yourself to #s fitting the buffer string length, you can:
Compute ceiling(log2(N)) - say L
Compute mask = 2^L
Loop until mask == 0:
& (bitwise and) the mask with the #. Print the result (1 or 0).
number &= (mask-1)
mask >>= 1 (divide by 2)
I assume this is related to your other question on extensible hashing.
First define some mnemonics for your bits:
const int FIRST_BIT = 0x1;
const int SECOND_BIT = 0x2;
const int THIRD_BIT = 0x4;
Then you have your number you want to convert to a bit string:
int x = someValue;
You can check if a bit is set by using the logical & operator.
if(x & FIRST_BIT)
{
// The first bit is set.
}
And you can keep an std::string and you add 1 to that string if a bit is set, and you add 0 if the bit is not set. Depending on what order you want the string in you can start with the last bit and move to the first or just first to last.
You can refactor this into a loop and using it for arbitrarily sized numbers by calculating the mnemonic bits above using current_bit_value<<=1 after each iteration.
There isn't a direct function, you can just walk along the bits of the int (hint see >> ) and insert a '1' or '0' in the string.
Sounds like a standard interview / homework type question
Use sprintf function to store the formatted output in the string variable, instead of printf for directly printing. Note, however, that these functions only work with C strings, and not C++ strings.
There's a small header only library you can use for this here.
Example:
std::cout << ConvertInteger<Uint32>::ToBinaryString(21);
// Displays "10101"
auto x = ConvertInteger<Int8>::ToBinaryString(21, true);
std::cout << x << "\n"; // displays "00010101"
auto x = ConvertInteger<Uint8>::ToBinaryString(21, true, "0b");
std::cout << x << "\n"; // displays "0b00010101"
Solution without reverse, no additional copy, and with 0-padding:
#include <iostream>
#include <string>
template <short WIDTH>
std::string binary( unsigned x )
{
std::string buffer( WIDTH, '0' );
char *p = &buffer[ WIDTH ];
do {
--p;
if (x & 1) *p = '1';
}
while (x >>= 1);
return buffer;
}
int main()
{
std::cout << "'" << binary<32>(0xf0f0f0f0) << "'" << std::endl;
return 0;
}
This is my best implementation of converting integers(any type) to a std::string. You can remove the template if you are only going to use it for a single integer type. To the best of my knowledge , I think there is a good balance between safety of C++ and cryptic nature of C. Make sure to include the needed headers.
template<typename T>
std::string bstring(T n){
std::string s;
for(int m = sizeof(n) * 8;m--;){
s.push_back('0'+((n >> m) & 1));
}
return s;
}
Use it like so,
std::cout << bstring<size_t>(371) << '\n';
This is the output in my computer(it differs on every computer),
0000000000000000000000000000000000000000000000000000000101110011
Note that the entire binary string is copied and thus the padded zeros which helps to represent the bit size. So the length of the string is the size of size_t in bits.
Lets try a signed integer(negative number),
std::cout << bstring<signed int>(-1) << '\n';
This is the output in my computer(as stated , it differs on every computer),
11111111111111111111111111111111
Note that now the string is smaller , this proves that signed int consumes less space than size_t. As you can see my computer uses the 2's complement method to represent signed integers (negative numbers). You can now see why unsigned short(-1) > signed int(1)
Here is a version made just for signed integers to make this function without templates , i.e use this if you only intend to convert signed integers to string.
std::string bstring(int n){
std::string s;
for(int m = sizeof(n) * 8;m--;){
s.push_back('0'+((n >> m) & 1));
}
return s;
}