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] );
}
Related
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).
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
I needed to convert a fractional part of a number into integer without a comma,
for example I have 3.35 I want to get just 35 part without zero or a comma,
Because I used the modf() function to extract the the fractional part but it gives me a 0.35
if there is any way to do that or to filter the '0.' part I will be very grateful if you show me how with the smaller code possible,
A bit more efficient than converting to a string and back again:
int fractional_part_as_int(double number, int number_of_decimal_places) {
double dummy;
double frac = modf(number,&dummy);
return round(frac*pow(10,number_of_decimal_places));
}
#include <iostream>
#include <cmath>
double round(double r) {
return (r > 0.0) ? std::floor(r + 0.5) : std::ceil(r - 0.5);
}
double floor_to_zero(double f) {
return (f > 0.0) ? std::floor(f) : std::ceil(f);
}
double sign(double s) {
return (s < 0.0) ? -1.0 : 1.0;
}
int frac(double f, int prec) {
return round((f - floor_to_zero(f)) * prec) * sign(f);
}
int main() {
double a = 1.2345;
double b = -34.567;
std::cout << frac(a, 100) << " " << frac(b, 100) << std::endl; // 23 57
}
another solution
int precision= 100;
double number = 3.35;
int f = floor(xx);
double temp = ( f - number ) * -1;
int fractional_part = temp * precision;
IF you need it as a string, a quite easy C style solution would be (should work for variable number of decimal places):
double yourNumber = 0.35f;
char buffer[32];
snprintf(buffer, 32, "%g", yourNumber);
strtok(buffer, "."); // Here we would get the part before . , should still check
char* fraction = strtok(NULL, ".");
int fractionAsInt = atoi(fraction);
This example lacks error handling in case of a bad string and is not feasible if you just need a fixed number of decimal places, since the arithmetic approaches work better there.
Something like this should work:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
static int get_frac(double value, unsigned short precision)
{
return (int)((value - (long)value) * pow(10, precision));
}
static int get_frac_no_trailing_zeros(double value, unsigned short precision)
{
int v = get_frac(value, precision);
while (v % 10 == 0)
v /= 10;
return v;
}
int main(int argc, char *argv[])
{
double v;
v = 123.4564;
printf("%.4f = %d\n", v, get_frac(v, 2));
printf("%.4f = %d\n", v, get_frac(v, 4));
printf("%.4f = %d\n", v, get_frac(v, 6));
printf("%.4f = %d\n", v, get_frac_no_trailing_zeros(v, 6));
return EXIT_SUCCESS;
}
You may also want to either avoid calling pow by having a user supply a number in a power of 10 in a first place, or use a lookup table.
Using some stl magic, here is the sample code:
typedef std::pair<int, int> SplitFloat;
SplitFloat Split(float value, int precision)
{
// Get integer part.
float left = std::floor(value);
// Get decimal part.
float right = (value - left) * float(std::pow(10, precision));
return SplitFloat(left, right);
}
It can be improved, but is pretty straightforward.
I just did something close to what you are trying to do, though I'm still pretty new. None the less, maybe this will help someone in the future as I landed here looking for results for my problem.
The first step is making sure that the variable that contains 3.35 is a double, but that's probably obvious.
Next, create a variable that is only an integer and set it's value equal to the value of the double. It will then only contain the whole number.
Then subtract the whole number (int) from the double. You will be left with the fraction/decimal value. From there, just multiply by 100.
Beyond the 100ths decimal value, you would have to do a little more configuring obviously, but it should be fairly simple to do with an if statement. If the decimal value is greater than .99, multiply 1000 instead etc..
Here's how I would do it.
#include <sstream>
#include <string>
int main()
{
double d = yourDesiredNumber; //this is your number
std::ostringstream out;
out << setprecision(yourDesiredPrecision) << std::fixed
<< std::showpoint << d;
std::istringstream in(out.str());
std::string wholePart; //you won't need this.
int fractionalPart;
std::getline(in, wholePart, '.');
in >> fractionalPart;
//now fractionalPart contains your desired value.
}
I'm pretty sure that instead of two different istringstream and ostringstream objects you could have gotten away with just one stringstream object, but I am not sure about the details (never used that class) so I didn't use it in the example.
When dealing with floating point values in Java, calling the toString() method gives a printed value that has the correct number of floating point significant figures. However, in C++, printing a float via stringstream will round the value after 5 or less digits. Is there a way to "pretty print" a float in C++ to the (assumed) correct number of significant figures?
EDIT: I think I am being misunderstood. I want the output to be of dynamic length, not a fixed precision. I am familiar with setprecision. If you look at the java source for Double, it calculates the number of significant digits somehow, and I would really like to understand how it works and/or how feasible it is to replicate this easily in C++.
/*
* FIRST IMPORTANT CONSTRUCTOR: DOUBLE
*/
public FloatingDecimal( double d )
{
long dBits = Double.doubleToLongBits( d );
long fractBits;
int binExp;
int nSignificantBits;
// discover and delete sign
if ( (dBits&signMask) != 0 ){
isNegative = true;
dBits ^= signMask;
} else {
isNegative = false;
}
// Begin to unpack
// Discover obvious special cases of NaN and Infinity.
binExp = (int)( (dBits&expMask) >> expShift );
fractBits = dBits&fractMask;
if ( binExp == (int)(expMask>>expShift) ) {
isExceptional = true;
if ( fractBits == 0L ){
digits = infinity;
} else {
digits = notANumber;
isNegative = false; // NaN has no sign!
}
nDigits = digits.length;
return;
}
isExceptional = false;
// Finish unpacking
// Normalize denormalized numbers.
// Insert assumed high-order bit for normalized numbers.
// Subtract exponent bias.
if ( binExp == 0 ){
if ( fractBits == 0L ){
// not a denorm, just a 0!
decExponent = 0;
digits = zero;
nDigits = 1;
return;
}
while ( (fractBits&fractHOB) == 0L ){
fractBits <<= 1;
binExp -= 1;
}
nSignificantBits = expShift + binExp +1; // recall binExp is - shift count.
binExp += 1;
} else {
fractBits |= fractHOB;
nSignificantBits = expShift+1;
}
binExp -= expBias;
// call the routine that actually does all the hard work.
dtoa( binExp, fractBits, nSignificantBits );
}
After this function, it calls dtoa( binExp, fractBits, nSignificantBits ); which handles a bunch of cases - this is from OpenJDK6
For more clarity, an example:
Java:
double test1 = 1.2593;
double test2 = 0.004963;
double test3 = 1.55558742563;
System.out.println(test1);
System.out.println(test2);
System.out.println(test3);
Output:
1.2593
0.004963
1.55558742563
C++:
std::cout << test1 << "\n";
std::cout << test2 << "\n";
std::cout << test3 << "\n";
Output:
1.2593
0.004963
1.55559
I think you are talking about how to print the minimum number of floating point digits that allow you to read the exact same floating point number back. This paper is a good introduction to this tricky problem.
http://grouper.ieee.org/groups/754/email/pdfq3pavhBfih.pdf
The dtoa function looks like David Gay's work, you can find the source here http://www.netlib.org/fp/dtoa.c (although this is C not Java).
Gay also wrote a paper about his method. I don't have a link but it's referenced in the above paper so you can probably google it.
Is there a way to "pretty print" a float in C++ to the (assumed) correct number of significant figures?
Yes, you can do it with C++20 std::format, for example:
double test1 = 1.2593;
double test2 = 0.004963;
double test3 = 1.55558742563;
std::cout << std::format("{}", test1) << "\n";
std::cout << std::format("{}", test2) << "\n";
std::cout << std::format("{}", test3) << "\n";
prints
1.2593
0.004963
1.55558742563
The default format will give you the shortest decimal representation with a round-trip guarantee like in Java.
Since this is a new feature and may not be supported by some standard libraries yet, you can use the {fmt} library, std::format is based on. {fmt} also provides the print function that makes this even easier and more efficient (godbolt):
fmt::print("{}", 1.2593);
Disclaimer: I'm the author of {fmt} and C++20 std::format.
You can use the ios_base::precision technique where you can specify the number of digits you want
For example
#include <iostream>
using namespace std;
int main () {
double f = 3.14159;
cout.unsetf(ios::floatfield); // floatfield not set
cout.precision(5);
cout << f << endl;
cout.precision(10);
cout << f << endl;
cout.setf(ios::fixed,ios::floatfield); // floatfield set to fixed
cout << f << endl;
return 0;
The above code with output
3.1416
3.14159
3.1415900000
There is a utility called numeric_limits:
#include <limits>
...
int num10 = std::numeric_limits<double>::digits10;
int max_num10 = std::numeric_limits<double>::max_digits10;
Note that IEEE numbers are not represented exactly bydecimal digits. These are binary quantities. A more accurate number is the number of binary bits:
int bits = std::numeric_limits<double>::digits;
To pretty print all the significant digits use setprecision with this:
out.setprecision(std::numeric_limits<double>::digits10);
What are the different techniques used to convert float type of data to integer in C++?
#include <iostream>
using namespace std;
struct database {
int id, age;
float salary;
};
int main() {
struct database employee;
employee.id = 1;
employee.age = 23;
employee.salary = 45678.90;
/*
How can i print this value as an integer
(with out changing the salary data type in the declaration part) ?
*/
cout << endl << employee.id << endl << employee.
age << endl << employee.salary << endl;
return 0;
}
What you are looking for is 'type casting'. typecasting (putting the type you know you want in brackets) tells the compiler you know what you are doing and are cool with it. The old way that is inherited from C is as follows.
float var_a = 9.99;
int var_b = (int)var_a;
If you had only tried to write
int var_b = var_a;
You would have got a warning that you can't implicitly (automatically) convert a float to an int, as you lose the decimal.
This is referred to as the old way as C++ offers a superior alternative, 'static cast'; this provides a much safer way of converting from one type to another. The equivalent method would be (and the way you should do it)
float var_x = 9.99;
int var_y = static_cast<int>(var_x);
This method may look a bit more long winded, but it provides much better handling for situations such as accidentally requesting a 'static cast' on a type that cannot be converted. For more information on the why you should be using static cast, see this question.
Normal way is to:
float f = 3.4;
int n = static_cast<int>(f);
Size of some float types may exceed the size of int.
This example shows a safe conversion of any float type to int using the int safeFloatToInt(const FloatType &num); function:
#include <iostream>
#include <limits>
using namespace std;
template <class FloatType>
int safeFloatToInt(const FloatType &num) {
//check if float fits into integer
if ( numeric_limits<int>::digits < numeric_limits<FloatType>::digits) {
// check if float is smaller than max int
if( (num < static_cast<FloatType>( numeric_limits<int>::max())) &&
(num > static_cast<FloatType>( numeric_limits<int>::min())) ) {
return static_cast<int>(num); //safe to cast
} else {
cerr << "Unsafe conversion of value:" << num << endl;
//NaN is not defined for int return the largest int value
return numeric_limits<int>::max();
}
} else {
//It is safe to cast
return static_cast<int>(num);
}
}
int main(){
double a=2251799813685240.0;
float b=43.0;
double c=23333.0;
//unsafe cast
cout << safeFloatToInt(a) << endl;
cout << safeFloatToInt(b) << endl;
cout << safeFloatToInt(c) << endl;
return 0;
}
Result:
Unsafe conversion of value:2.2518e+15
2147483647
43
23333
For most cases (long for floats, long long for double and long double):
long a{ std::lround(1.5f) }; //2l
long long b{ std::llround(std::floor(1.5)) }; //1ll
Check out the boost NumericConversion library. It will allow to explicitly control how you want to deal with issues like overflow handling and truncation.
I believe you can do this using a cast:
float f_val = 3.6f;
int i_val = (int) f_val;
the easiest technique is to just assign float to int, for example:
int i;
float f;
f = 34.0098;
i = f;
this will truncate everything behind floating point or you can round your float number before.
One thing I want to add. Sometimes, there can be precision loss. You may want to add some epsilon value first before converting. Not sure why that works... but it work.
int someint = (somedouble+epsilon);
This is one way to convert IEEE 754 float to 32-bit integer if you can't use floating point operations. It has also a scaler functionality to include more digits to the result. Useful values for scaler are 1, 10 and 100.
#define EXPONENT_LENGTH 8
#define MANTISSA_LENGTH 23
// to convert float to int without floating point operations
int ownFloatToInt(int floatBits, int scaler) {
int sign = (floatBits >> (EXPONENT_LENGTH + MANTISSA_LENGTH)) & 1;
int exponent = (floatBits >> MANTISSA_LENGTH) & ((1 << EXPONENT_LENGTH) - 1);
int mantissa = (floatBits & ((1 << MANTISSA_LENGTH) - 1)) | (1 << MANTISSA_LENGTH);
int result = mantissa * scaler; // possible overflow
exponent -= ((1 << (EXPONENT_LENGTH - 1)) - 1); // exponent bias
exponent -= MANTISSA_LENGTH; // modify exponent for shifting the mantissa
if (exponent <= -(int)sizeof(result) * 8) {
return 0; // underflow
}
if (exponent > 0) {
result <<= exponent; // possible overflow
} else {
result >>= -exponent;
}
if (sign) result = -result; // handle sign
return result;
}