[Rewritten for clarity.]
I need to write and read doubles to and from files, in a format that will always have the same number of characters. The format doesn't need to be human-readable: it just needs to be quick to load (with as little dynamic memory and conversion stuff as possible, file space is important but doesn't matter quite as much).
Is there a standard (or at least safe and reliable) way to get the components of a double so that I can store the signicicand sign and mantissa sign as a '1' or '0' and the significand and mantissa separately in a hex format with a constant length?
Essentially, how can I grab the specific bit/number components from a double? Is it even possible to do this on separate systems (assuming the same OS family such as Windows) or is the standard for the components of doubles not enforced per OS?
I am using MinGW and of course compiling for Windows. I'd like to use the C Standard Library where possible, not the C++ Standard Library. Also, I'd like to avoid other libraries (like Boost) but if there are specific Windows functions then those would help a lot.
The most direct way of doing so would be to open your fstream in binary mode, and then use the write() and read() methods of fstream to read your double to/from the stream:
#include <fstream>
#include <iostream>
int main( int argc, char** argv ) {
std::fstream fp( "foo", std::fstream::in |
std::fstream::out |
std::fstream::trunc |
std::fstream::binary );
double d1, d2;
d1 = 3.14;
fp.write( (char*)&d1, sizeof( d1 ) );
fp.seekg( 0, std::fstream::beg );
fp.read( (char*)&d2, sizeof( d2 ) );
std::cout << "d1 = " << d1 << " d2 = " << d2 << std::endl;
}
Probably you want somthing like this:
#include <iostream>
#include <sstream>
#include <iomanip>
using namespace std;
template <typename T>
string convertToHex(const T &x)
{
char *xc = (char *)&x;
ostringstream s;
for (char *c = xc; c < xc + sizeof(x); ++c)
s << hex << setw(2) << setfill('0') << static_cast<int>(*c) << " ";
return s.str();
}
template <typename T>
void convertFromHex(string s, T &x)
{
char *xc = (char *)&x;
istringstream is(s);
for (char *c = xc; c < xc + sizeof(x); ++c)
{
int tmp;
is >> hex >> tmp;
*c = tmp;
}
}
int main()
{
double a = 10;
string as = convertToHex(a);
cout << "a: " << as << endl;
double b;
convertFromHex(as, b);
cout << "b: " << b << endl;
}
Output:
a: 00 00 00 00 00 00 24 40
b: 10
Here is very very simple example with boost::serializer (http://www.boost.org/doc/libs/1_54_0/libs/serialization/doc/index.html). I am using boost::archive::text_iarchive and boost::archive::text_oarchive, but you can switch it to boost::archive::binary_iarchive and boost::archive::binary_oarchive. Should work.
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <sstream>
#define _USE_MATH_DEFINES
#include <cmath>
using namespace std;
int main()
{
double a = M_PI;
string text;
{
ostringstream textStream;
boost::archive::text_oarchive oa(textStream);
oa << a;
text = textStream.str();
}
cout << "a: " << text << endl;
double b;
{
istringstream textStream(text);
boost::archive::text_iarchive ia(textStream);
ia >> b;
}
cout << "b: " << b << endl;
}
Output:
a: 22 serialization::archive 9 3.1415926535897931
b: 3.14159
Related
This question already has answers here:
C++ cout hex values?
(10 answers)
Closed 2 years ago.
My code:
#include <iostream>
using namespace std;
int main() {
unsigned int a = 0x0009, b = 0x0002;
unsigned int c = a + b;
cout << c;
}
Now
c = 11
I want to this:
c = 000B
How can I do ?
When you do this
int main() {
unsigned int a = 0x0009, b = 0x0002;
unsigned int c = a + b;
}
Then c has the value of 11, it also has the value of 0x000B. It also has the value of 10 in a representation that uses 11 as base.
11 and 0x000B (and 10) are different representations of the same value.
When you use std::cout then the number is printed as decimal by default. What representation you choose to print the value on the screen has no influence whatsoever on the actual value of c.
What I understand is that you want to retrieve the result in an hexadecimal specific format XXXX.
Computing the addition is the same as any number base, you only need to use (here I display) the result in your format.
You can do this, for instance:
#include <iostream>
#include <iomanip>
std::string displayInPersonalizedHexa(unsigned int a)
{
std::stringstream ss;
ss << std::uppercase<< std::setfill('0') << std::setw(4) << std::hex<< a;
std::string x;
ss >>x;
//std::cout << x;
return x;
}
int main() {
unsigned int a = 0x0009, b = 0x0002;
unsigned int c = a + b;
// displays 000B
std::cout << displayInPersonalizedHexa(c) << std::endl;
// adds c=c+1
c=c+1;
// displays 000C
std::cout << displayInPersonalizedHexa(c) << std::endl;
//0xC+5 = 0x11
c=c+5;
// displays 0011
std::cout << displayInPersonalizedHexa(c) << std::endl;
}
This will output
000B
000C
0011
I need to create file with specific file name format (on windows). the format is:
Name_nodeNum_frequency.txt
nodeNum is int and frequency is float.
those two variables should be written with fixed digits:
if nodeNum is 8 --> 008
if frequency is 4.88421 --> 4.884
this is the function:
create_file(int nodeNum, double frequency)
{
char buffer [50];
//convert int to string
itoa(nodeNum, buffer, 10);
string sNodeNum = string(buffer);
//not sure about the double
//tried to_string but I got:
// more than instance of overloaded function matches the argument list
string fileName = ("Name_" + sNodeNum + "_" + sfreq + "MHZ");
FILE* pFile = OpenFile(fileName);
}
I tried to use %d, but it seems like I should not do that:
string fileName = ("Delay_" + "%3d" + "_" + sfreq + "MHZ" , sNodeNum);
I will be happy for some guidance.
thanks!
You seem to be mixing C and C++ here. A simple way to do this in C would be:
#include <stdio.h>
int main()
{
int sNodeNum = 8;
double sfreq = 4.88421;
char filename[50];
sprintf(filename, "Delay_%03d_%.3fMHZ.txt", sNodeNum, sfreq);
FILE* pFile = fopen(filename, "w");
return 0;
}
If on the other hand, if you want to use C++, you should make a few changes:
#include <iomanip>
#include <fstream>
#include <sstream>
#include <iostream>
int main()
{
int sNodeNum = 8;
double sfreq = 4.88421;
std::ostringstream ss;
ss << "Delay_" << std::setfill('0') << std::setw(3) << sNodeNum
<< "_" << std::setprecision(4) << sfreq << "MHZ.txt";
std::string filename(ss.str());
std::ofstream fout(filename.c_str());
return 0;
}
Each of these two approaches opens a file for writing, with the name Delay_008_4.884MHZ.txt.
Live demo link
#include <string>
#include <iomanip>
#include <iostream>
int nodeNum = 8;
float frequency = 4.88421f;
std::ostream& out = std::cout; // put your std::ofstream file or std::ostringstream
std::ios::fmtflags flags = out.flags();
out.width(3);
out.fill('0');
out.setf(std::ios::right, std::ios::adjustfield);
out << nodeNum << std::endl;
flags = out.flags(flags);
out.precision(3);
out.setf(std::ios::fixed, std::ios::floatfield);
out << frequency;
out.flags(flags);
Or even simpler:
out << std::setw(3) << std::setfill('0') << std::right << nodeNum << std::endl;
out << std::setprecision(3) << std::fixed << frequency;
Output:
008
4.884
I'm loosing my mind at the moment and below is what I'm trying to do.
char* buffer;
sprintf(buffer, "0x%08x", 5);
*(int *)(0x834AF2AC + 0x1a) = ?buffer?;
Buffer = 0x05000000
I need to set that in memory, if I just set 05 it will set 0x00000005
Question asked better.
How can I convert an INT into a format of "0x%08x"
So 5 becomes 0x05000000
ANSWERD:
The correct answer is *(int *)(0x834AF2AC + 0x1a) = 5<<24;
Something like this:
#include <iostream> // for std::cout, std::endl
#include <string> // for std::string, std::stoi
int main()
{
std::string s{"0x05"};
int i = std::stoi(s, nullptr, 16); // convert base 16 number in s to int
std::cout << i << std::endl;
}
Two result from google which points to stackoverflow (result 1 and 2).
Convert char to int in C and C++
C char* to int conversion
I'm not sure if I understand correctly but if you want to convert an entire string to int, then I would suggest stringstream.
http://www.cplusplus.com/reference/sstream/stringstream/stringstream/
For hexadecimal string:
#include <string> // std::string
#include <iostream> // std::cout
#include <sstream> // std::stringstream
int main () {
std::stringstream ss;
ss << std::hex << 0x05;
int foo;
ss >> foo;
std::cout << "foo: " << foo << '\n';
return 0;
}
I have a string: (66)
Then I convert it to double and do some math: atof(t.c_str()) / 30
then I convert it back to string: string s = boost::lexical_cast<string>(hizdegerd)
Problem is when I show it on label it becomes 2,20000001.
I've tried everything. sprintf etc.
I want to show only one digit after point.
hizdegerd = atof(t.c_str()) / 30;
char buffer [50];
hizdegerd=sprintf (buffer, "%2.2f",hizdegerd);
if(oncekideger != hizdegerd)
{
txtOyunHiz->SetValue(hizdegerd);
oncekideger = hizdegerd;
}
I think I'd wrap the formatting up into a function template, something like this:
#include <iostream>
#include <sstream>
#include <iomanip>
template <class T>
std::string fmt(T in, int width = 0, int prec = 0) {
std::ostringstream s;
s << std::setw(width) << std::setprecision(prec) << in;
return s.str();
}
int main(){
std::string s = fmt(66.0 / 30.0, 2, 2);
std::cout << s << "\n";
}
You can use this way of conversion back to string and then only the wished number of digits for the precision will be taken in consideration:
ostringstream a;
a.precision(x); // the number of precision digits will be x-1
double b = 1.45612356;
a << b;
std::string s = a.str();
Since you wrote "I want to show":
#include<iostream>
#include<iomanip>
int main()
{
std::cout << std::fixed << std::setprecision(1) << 34.2356457;
}
Output:
34.2
By the way, sprintf is buffer-overflow-vulnerable and is not C++ .
Hello
I know it was asked many times but I hadn't found answer to my specific question.
I want to convert only string that contains only decimal numbers:
For example 256 is OK but 256a is not.
Could it be done without checking the string?
Thanks
The simplest way that makes error checking optional that I can think of is this:
char *endptr;
int x = strtol(str, &endptr, 0);
int error = (*endptr != '\0');
In C++ way, use stringstream:
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main()
{
stringstream sstr;
int a = -1;
sstr << 256 << 'a';
sstr >> a;
if (sstr.failbit)
{
cout << "Either no character was extracted, or the character can't represent a proper value." << endl;
}
if (sstr.badbit)
{
cout << "Error on stream.\n";
}
cout << "Extracted number " << a << endl;
return 0;
}
An other way using c++ style : We check the number of digits to know if the string was valid or not :
#include <iostream>
#include <sstream>
#include <string>
#include <cmath>
int main(int argc,char* argv[]) {
std::string a("256");
std::istringstream buffer(a);
int number;
buffer >> number; // OK conversion is done !
// Let's now check if the string was valid !
// Quick way to compute number of digits
size_t num_of_digits = (size_t)floor( log10( abs( number ) ) ) + 1;
if (num_of_digits!=a.length()) {
std::cout << "Not a valid string !" << std::endl;
}
else {
std::cout << "Valid conversion to " << number << std::endl;
}
}