How do you output variable's declared as a double to a text file in C++ - c++

I am very new to C++ and I am wondering how you output/write variables declared as double to a txt file. I know about how to output strings using fstream but I cant figure out how to send anything else. I am starting to think that you can't send anything but strings to a text file is that correct? If so then how would you convert the information stored in the variable to a string variable?
Here is my code that I'm trying to implement this concept into, Its fairly simple:
int main()
{
double invoiceAmt = 3800.00;
double apr = 18.5; //percentage
//compute cash discount
double discountRate = 3.0; //percentage
double discountAmt;
discountAmt = invoiceAmt * discountRate/100;
//compute amount due in 10 days
double amtDueIn10;
amtDueIn10 = invoiceAmt - discountAmt;
//Compute Interest on the loan of amount (with discount)for 20 days
double LoanInt;
LoanInt = amtDueIn10 * (apr /360/100) * 20;
//Compute amount due in 20 days at 18.5%.
double amtDueIn20;
amtDueIn20 = invoiceAmt * (1 + (apr /360/100) * 20);
return 0;
}
So what I'm trying to do is use those variables and output them to the text file. Also please inform me on the includes that I need to use for this source code. Feel free to give suggestions on how to improve my code in other ways as well please.
Thanks in advance.

As your tagging suggests, you use file streams:
std::ofstream ofs("/path/to/file.txt");
ofs << amtDueIn20;
Depending on what you need the file for, you'll probably have to write more stuff (like whitespaces etc.) in order to get decent formatting.
Edit due to rmagoteaux22's ongoing problems:
This code
#include <iostream>
#include <fstream>
const double d = 3.1415926;
int main(){
std::ofstream ofs("test.txt");
if( !ofs.good() ) {
std::cerr << "Couldn't open text file!\n";
return 1;
}
ofs << d << '\n';
return 0;
}
compiles for me (VC9) and writes this to test.txt:
3.14159
Can you try this?

Simply use the stream write operator operator<< which has an overloaded definition for double (defined in basic_ostream)
#include <fstream>
...
std::fstream stmMyStream( "c:\\tmp\\teststm.txt", std::ios::in | std::ios::out | std::ios::trunc );
double dbMyDouble = 23.456;
stmMyStream << "The value is: " << dbMyDouble;

To answer your first question, in C you use printf (and for file output fprintf). IIRC, cout has a large number of modifiers also, but I won't mention them as you originally mentioned fstream (more 'C' centric than C++) --
oops, missed the ofstream indicator, ignore my 'C' comments and use C++
to improve your program, be sure to use parentheses a lot when doing computations as above to be 100% sure things are evaluated the way you want them to be (do not rely on order of precedence)

Generally speaking methods to write to a output are printf, wprintf etc.
In case of files, these methods are named as fprintf_s, fsprintf_s etc.
Note that the '_s' methods are the new secure variations of previous formatting methods. You should always use these new secure versions.
For examples refer to:
http://msdn.microsoft.com/en-us/library/ksf1fzyy%28VS.80%29.aspx
Note these methods use a format specifier to convert a given type to text. For example %d acts as a place holder for integer. Similarly %f for double.

Just use the << operator on an output stream:
#include <fstream>
int main() {
double myNumber = 42.5;
std::fstream outfile("test.txt", std::fstream::out);
outfile << "The answer is almost " << myNumber << std::endl;
outfile.close();
}

I was having the exact same problem, where ofstream was outputting strings, but stopped as soon as it reached a variable. With a bit more Googling I found this solution in a forum post:
Under Xcode 3.2 when creating a new project based on stdc++ project template the target build settings for Debug configuration adds preprocessor macros which are incompatible with gcc-4.2:
_GLIBCXX_DEBUG=1
_GLIBXX_DEBUG_PEDANTIC=1
Destroy them if you want Debug/gcc-4.2 to execute correctly.
http://forums.macrumors.com/showpost.php?p=8590820&postcount=8

Related

Bug writing into Excel file - C++

When I send a variable into Excel it changes its value. It just happens with excel. It also just happens when the variable is stored in a container. I guess it is more clear if you see the code:
#include<iostream>
#include<array>
#include<vector>
#include<fstream>
const int aSize{ 150000 };
std::array<double, aSize> anArray{};
int main(void)
{
double aValue{ 0.00000005467 };
std::vector<double> aVector;
for (int i = 0; i < aSize; ++i)
{
anArray[i] = aValue;
aVector.push_back(aValue);
}
std::ofstream fileOne, fileTwo, fileThree, fileFour, fileFive;
fileOne.open("array.xls");
fileTwo.open("array.txt");
fileThree.open("vector.xls");
fileFour.open("vector.txt");
fileFive.open("value.xls");
fileOne << anArray[0];
fileTwo << anArray[0];
fileThree << aVector[0];
fileFour << aVector[0];
fileFive << aValue;
std::cout << aValue << "\n" << anArray[0] << "\n" << aVector[0];
return 0;
}
All I do is populate a vector and an array. If I print the value of the variable I get the expected value. If I send it into a .txt I get the expected value. If I send just the value into Excel I get the expected value.
It all just breakes down when I send the value from the containers into Excel. Why can this be happening?
What seems likely to be the problem here is the way the Excel is interpreting the (formatted) numerical output from your c++ program. Even though the text may be correct (from the point of view of the cout function) it may not have the 'correct' decimal point character in it (i.e. a dot instead of a comma, or vice versa).
Solution: Make sure that Excel is set to use the same "locale" as the default c++ locale, or set the c++ locale to whatever Excel is using.
The MS-XLS file format is not a simple text file. You cannot simply put text into it and expect it to show up correctly. You would need more code and/or specialized libraries to interact with it.
See the suggestions here.

Issues saving double as binary in c++

In my simulation code for a particle system, I have a class defined for particles, and each particle has a property of pos containing its position, which is a double pos[3]; as there are 3 coordinate components per particle. So with particle object defined by particles = new Particle[npart]; (as we have npart many particles), then e.g. the y-component of the 2nd particle would be accessed with double dummycomp = particles[1].pos[1];
To save the particles to file before using binary I would use (saved as txt, with float precision of 10 and one particle per line):
#include <iostream>
#include <fstream>
ofstream outfile("testConfig.txt", ios::out);
outfile.precision(10);
for (int i=0; i<npart; i++){
outfile << particle[i].pos[0] << " " << particle[i].pos[1] << " " << particle[i].pos[2] << endl;
}
outfile.close();
But now, to save space, I am trying to save the configuration as a binary file, and my attempt, inspired from here, has been as follows:
ofstream outfile("test.bin", ios::binary | ios::out);
for (int i=0; i<npart; i++){
outfile.write(reinterpret_cast<const char*>(particle[i].pos),streamsize(3*sizeof(double)));
}
outfile.close();
but I am facing a segmentation fault when trying to run it. My questions are:
Am I doing something wrong with reinterpret_cast or rather in the argument of streamsize()?
Ideally, it would be great if the saved binary format could also be read within Python, is my approach (once fixed) allowing for that?
working example for the old saving approach (non-binary):
#include <iostream>
#include <fstream>
using namespace std;
class Particle {
public:
double pos[3];
};
int main() {
int npart = 2;
Particle particles[npart];
//initilizing the positions:
particles[0].pos[0] = -74.04119568;
particles[0].pos[1] = -44.33692582;
particles[0].pos[2] = 17.36278231;
particles[1].pos[0] = 48.16310086;
particles[1].pos[1] = -65.02325252;
particles[1].pos[2] = -37.2053818;
ofstream outfile("testConfig.txt", ios::out);
outfile.precision(10);
for (int i=0; i<npart; i++){
outfile << particles[i].pos[0] << " " << particles[i].pos[1] << " " << particles[i].pos[2] << endl;
}
outfile.close();
return 0;
}
And in order to save the particle positions as binary, substitute the saving portion of the above sample with
ofstream outfile("test.bin", ios::binary | ios::out);
for (int i=0; i<npart; i++){
outfile.write(reinterpret_cast<const char*>(particles[i].pos),streamsize(3*sizeof(double)));
}
outfile.close();
2nd addendum: reading the binary in Python
I managed to read the saved binary in python as follows using numpy:
data = np.fromfile('test.bin', dtype=np.float64)
data
array([-74.04119568, -44.33692582, 17.36278231, 48.16310086,
-65.02325252, -37.2053818 ])
But given the doubts cast in the comments regarding non-portability of binary format, I am not confident this type of reading in Python will always work! It would be really neat if someone could elucidate on the reliability of such approach.
The trouble is that base 10 representation of double in ascii is flawed and not guaranteed to give you the correct result (especially if you only use 10 digits). There is a potential for a loss of information even if you use all std::numeric_limits<max_digits10> digits as the number may not be representable in base 10 exactly.
The other issue you have is that the binary representation of a double is not standardized so using it is very fragile and can lead to code breaking very easily. Simply changing the compiler or compiler sittings can result in a different double format and changing architectures you have absolutely no guarantees.
You can serialize it to text in a non lossy representation by using the hex format for doubles.
stream << std::fixed << std::scientific << particles[i].pos[0];
// If you are using C++11 this was simplified to
stream << std::hexfloat << particles[i].pos[0];
This has the affect of printing the value with the same as "%a" in printf() in C, that prints the string as "Hexadecimal floating point, lowercase". Here both the radix and mantissa are converted into hex values before being printed in a very specific format. Since the underlying representation is binary these values can be represented exactly in hex and provide a non lossy way of transferring data between systems. IT also truncates proceeding and succeeding zeros so for a lot of numbers is relatively compact.
On the python side. This format is also supported. You should be able to read the value as a string then convert it to a float using float.fromhex()
see: https://docs.python.org/3/library/stdtypes.html#float.fromhex
But your goal is to save space:
But now, to save space, I am trying to save the configuration as a binary file.
I would ask the question do you really need to save space? Are you running on a low powered low resource environment? Sure then space saving can definitely be a thing (but that is rare nowadays (but these environments do exist)).
But it seems like you are running some form of particle simulation. This does not scream low resource use case. Even if you have tera bytes of data I would still go with a portable easy to read format over binary. Preferably one that is not lossy. Storage space is cheap.
I suggest using a library instead of writing a serialization/deserialization routine from scratch. I find cereal really easy to use, maybe even easier than boost::serialization. It reduces the opportunity for bugs in your own code.
In your case I'd go about serializing doubles like this using cereal:
#include <cereal/archives/binary.hpp>
#include <fstream>
int main() {
std::ofstream outfile("test.bin", ios::binary);
cereal::BinaryOutputArchive out(outfile);
double x, y, z;
x = y = z = 42.0;
out(x, y, z);
}
To deserialize them you'd use:
#include <cereal/archives/binary.hpp>
#include <fstream>
int main() {
std::ifstream infile("test.bin", ios::binary);
cereal::BinaryInputArchive in(infile);
double x,y,z;
in(x, y, z);
}
You can also serialize/deserialize whole std::vector<double>s in the same fashion. Just add #include <cereal/types/vector.hpp> and use in / out like in the given example on a single std::vector<double> instead of multiple doubles.
Ain't that swell.
Edit
In a comment you asked, whether it'd be possible to read a created binary file like that with Python.
Answer:
Serialized binary files aren't really meant to be very portable (things like endianness could play a role here). You could easily adapt the example code I gave you to write a JSON file (another advantage of using a library) and read that format in Python.
Oh and cereal::JSONOutputArchive has an option for setting precision.
Just curious if you ever investigated the idea of converting your data to vectored coordinates instead of Cartesian X,Y,Z? It would seem that this would potentially reduce the size of your data by about 30%: Two coordinates instead of three, but perhaps needing slightly higher precision in order to convert back to your X,Y,Z.
The vectored coordinates could still be further optimized by using the various compression techniques above (text compression or binary conversion).

ifstream / ofstream issue with c++?

I have been having a very hard time writing to a binary file and reading back. I am basically writing records of this format
1234|ABCD|efgh|IJKL|ABC
Before writing this record, I would write the length of this entire record ( using string.size()) and then I write the record to the binary file using ofstream as follows:
int size;
ofstream studentfile;
studentfile.open( filename.c_str(),ios::out|ios::binary );
studentfile.write((char*)&size,sizeof(int));
studentfile.write(data.c_str(),(data.size()*(sizeof(char))));
cout << "Added " << data << " to " << filename << endl;
studentfile.close();
And I read this data at some other place
ifstream ifile11;
int x;
std::string y;
ifile11.open("student.db", ios::in |ios::binary);
ifile11.read((char*)&x,sizeof(int));
ifile11.read((char*)&y,x);
cout << "X " << x << " Y " << y << endl;
first I read the length of the record into the variable x, and then read the record into string y. The problem is, the output shows x as being '0' and 'y' is empty.
I am not able figure this out. Someone who can look into this problem and provide some insight will be thanked very much.
Thank you
You can't read a string that way, as a std::string is really only a pointer and a size member. (Try doing std::string s; sizeof(s), the size will be constant no matter what you set the string to.)
Instead read it into a temporary buffer, and then convert that buffer into a string:
int length;
ifile11.read(reinterpret_cast<char*>(&length), sizeof(length));
char* temp_buffer = new char[length];
ifile11.read(temp_buffer, length);
std::string str(temp_buffer, length);
delete [] temp_buffer;
I know I am answering my own question, but I strictly feel this information is going to help everyone. For most part, Joachim's answer is correct and works. However, there are two main issues behind my problem :
1. The Dev-C++ compiler was having a hard time reading binary files.
2. Not passing strings properly while writing to the binary file, and also reading from the file. For the reading part, Joachim's answer fixed it all.
The Dev-C++ IDE didn't help me. It wrongly read data from the binary file, and it did it without me even making use of a temp_buffer. Visual C++ 2010 Express has correctly identified this error, and threw run-time exceptions and kept me from being misled.
As soon as I took all my code into a new VC++ project, it appropriately provided me with error messages, so that I could fix it all.
So, please do not use Dev-C++ unless you want to run into real troubles like thiis. Also, when trying to read strings, Joachim's answer would be the ideal way.

Create an array with external file in C++

I have 4 days of training in C++, so bear with me.
Two data files are required to evaluate a multiple-choice examination. The first file
(booklet.dat) contains the correct answers. The total number of questions is 50. A sample
file is given below:
ACBAADDBCBDDAACDBACCABDCABCCBDDABCACABABABCBDBAABD
The second file (answer.dat) contains the students’ answers. Each line has one student
record that contains the following information:
The student’s answers (a total of 50 answers) in the same format as above (* indicates no answer)., followed by Student ID and Student Name. Example:
AACCBDBC*DBCBDAAABDBCBDBAA*BCBDD*BABDBCDAABDCBDBDA 6555 MAHMUT
CBBDBC*BDBDBDBABABABBBBBABBABBBBD*BBBCBBDBABBBDC** 6448 SINAN
ACB*ADDBCBDDAACDBACCABDCABCCBDDABCACABABABCBDBAABD 6559 CAGIL
I have a homework assignment to write a C++ program that counts the total number of correct answers by each student and outputs this information to another file called report.dat. In this file, the student’s IDs, names and scores must be given. Each correct answer is worth 1 point. For the sample files given above, the output should be as follows:
6555 MAHMUT 10
6448 SINAN 12
6550 CAGIL 49
Here's what I have so far:
include <iostream>
include <fstream>
using namespace std;
int main()
{
char booklet[50] answers[50]
int counter
// Link answers with booklet.dat
booklet = ifstream
input_file("booklet.dat");
return 0;
// Link answers with answers.dat
answers = ifstream
input_file("answer.dat");
return 0;
while (booklet==answers)
{
counter++
cout << "The student had">>counter>> "answers right";
}
}
I'm not even sure I am in the correct direction. I know I need to create an array from the file booklet.dat and another one from the file answer.dat. Then the comparison has to be made and the matches between the two have to be counted.
I don't expect anyone to do the assignment for me, i just need a nudge in the right direction.
1.) On your Syntax:
a) Each line in C++ has to end with an ";". There are some lines in your excample which don't. (Normally your compile should point at this or the following line with an error)
b) Multiple variable definitions need a "," in between two different variables.
2.) I would recommend you to use something like that:
(have a look at C++ Reference fstream)
EDIT: just a little outline, which is not complete in this form, just to give you and idea ;-)
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main()
{
int nr_of_students = 1000; /* Or any number you'd like to analyze */
int stud_nr[nr_of_students];
string stud_name[nr_of_students];
int stud_count[nr_of_students];
fstream in_out;
in_out.open("filename.dat",fstream::in); // fstream::in for reading from file
// fstream::out for writing to this file
if(in_out.is_open())
{
for(lines=0;(in_out>>answers && lines<nr_of_students);lines++)
{
in_out >> stud_nr[lines]; /* EDIT: sorry hat some index confusions here... */
in_out >> stud_name[lines];
stud_count[lines]=0;
for(int i=0;i<50;i++)
{
/* comparison between the booklet_array and the answers_array */
/* Count up the stud_count[lines] for each right comparison */
}
}
/* some simmilar code for the output-file */
}
else cout << "Error reading " << "filename.dat" << endl;
return 1;
}
3.) Your code would also get more performance with vectors.
A good Tutorial would be: Tutorial part I
and you find part 2 in the comments there
4.) you can achieve a more dynamic code with argc and argv**, just google for that
I hope these comments help you a little bit to carry on ;)
You are already on the right direction. Basically you want to load the answer key into an array for fast comparison and then you need to check the answers of each student and each time they get a correct answer you increment a counter and write the ID, name and score for each student. There are problems with your code such as missing semicolons.
Also please note that returning exits a function and that no statements after an unconditional return are executed, returning from main terminates your program.
The normal approach to open a file for reading is:
#include<fstream>
#include<string>
int main()
{
std::ifstream input_file("inputfilename");
// since the answer key is one line
// and each students answer , id and name are also one line
// getting that line using std::getline() would be sufficient
std::string line;
std::getline(input_file, line);
// line would now contain the entire first line except the newline character
std::getline(input_file, line);
//now line would now contain the second line in the file
return 0;
}
Writing to a file is similar we use ofstream to open a file for writing.
Like so:
#include<fstream>
int main()
{
std::ofstream output_file("outputfilename");
// lets say we have a string and an int that we want to write
std::string line_to_write("Hello File");
int number = 42;
output_file << line_to_write << number; // writes the string and then 42 on the same line
output_file << '\n'; // writes the newline character so that next writes would appear on another line
return 0;
}
For references to the standard library and C++ in general when you need to know the available functions to do something I recommend cppreference here are the specific pages on ifstream and ofstream.

C++ - string.compare issues when output to text file is different to console output?

I'm trying to find out if two strings I have are the same, for the purpose of unit testing. The first is a predefined string, hard-coded into the program. The second is a read in from a text file with an ifstream using std::getline(), and then taken as a substring. Both values are stored as C++ strings.
When I output both of the strings to the console using cout for testing, they both appear to be identical:
ThisIsATestStringOutputtedToAFile
ThisIsATestStringOutputtedToAFile
However, the string.compare returns stating they are not equal. When outputting to a text file, the two strings appear as follows:
ThisIsATestStringOutputtedToAFile
T^#h^#i^#s^#I^#s^#A^#T^#e^#s^#t^#S^#t^#r^#i^#n^#g^#O^#u^#t^#p^#u^#t^#
t^#e^#d^#T^#o^#A^#F^#i^#l^#e
I'm guessing this is some kind of encoding problem, and if I was in my native language (good old C#), I wouldn't have too many problems. As it is I'm with C/C++ and Vi, and frankly don't really know where to go from here! I've tried looking at maybe converting to/from ansi/unicode, and also removing the odd characters, but I'm not even sure if they really exist or not..
Thanks in advance for any suggestions.
EDIT
Apologies, this is my first time posting here. The code below is how I'm going through the process:
ifstream myInput;
ofstream myOutput;
myInput.open(fileLocation.c_str());
myOutput.open("test.txt");
TEST_ASSERT(myInput.is_open() == 1);
string compare1 = "ThisIsATestStringOutputtedToAFile";
string fileBuffer;
std::getline(myInput, fileBuffer);
string compare2 = fileBuffer.substr(400,100);
cout << compare1 + "\n";
cout << compare2 + "\n";
myOutput << compare1 + "\n";
myOutput << compare2 + "\n";
cin.get();
myInput.close();
myOutput.close();
TEST_ASSERT(compare1.compare(compare2) == 0);
How did you create the content of myInput? I would guess that this file is created in two-byte encoding. You can use hex-dump to verify this theory, or use a different editor to create this file.
The simpliest way would be to launch cmd.exe and type
echo "ThisIsATestStringOutputtedToAFile" > test.txt
UPDATE:
If you cannot change the encoding of the myInput file, you can try to use wide-chars in your program. I.e. use wstring instead of string, wifstream instead of ifstream, wofstream, wcout, etc.
The following works for me and writes the text pasted below into the file. Note the '\0' character embedded into the string.
#include <iostream>
#include <fstream>
#include <sstream>
int main()
{
std::istringstream myInput("0123456789ThisIsATestStringOutputtedToAFile\x0 12ou 9 21 3r8f8 reohb jfbhv jshdbv coerbgf vibdfjchbv jdfhbv jdfhbvg jhbdfejh vbfjdsb vjdfvb jfvfdhjs jfhbsd jkefhsv gjhvbdfsjh jdsfhb vjhdfbs vjhdsfg kbhjsadlj bckslASB VBAK VKLFB VLHBFDSL VHBDFSLHVGFDJSHBVG LFS1BDV LH1BJDFLV HBDSH VBLDFSHB VGLDFKHB KAPBLKFBSV LFHBV YBlkjb dflkvb sfvbsljbv sldb fvlfs1hbd vljkh1ykcvb skdfbv nkldsbf vsgdb lkjhbsgd lkdcfb vlkbsdc xlkvbxkclbklxcbv");
std::ofstream myOutput("test.txt");
//std::ostringstream myOutput;
std::string str1 = "ThisIsATestStringOutputtedToAFile";
std::string fileBuffer;
std::getline(myInput, fileBuffer);
std::string str2 = fileBuffer.substr(10,100);
std::cout << str1 + "\n";
std::cout << str2 + "\n";
myOutput << str1 + "\n";
myOutput << str2 + "\n";
std::cout << str1.compare(str2) << '\n';
//std::cout << myOutput.str() << '\n';
return 0;
}
Output:
ThisIsATestStringOutputtedToAFile
ThisIsATestStringOutputtedToAFile
It turns out that the problem was that the file encoding of myInput was UTF-16, whereas the comparison string was UTF-8. The way to convert them with the OS limitations I had for this project (Linux, C/C++ code), was to use the iconv() functions. To keep the compatibility of the C++ strings I'd been using, I ended up saving the string to a new text file, then running iconv through the system() command.
system("iconv -f UTF-16 -t UTF-8 subStr.txt -o convertedSubStr.txt");
Reading the outputted string back in then gave me the string in the format I needed for the comparison to work properly.
NOTE
I'm aware that this is not the most efficient way to do this. I've I'd had the luxury of a Windows environment and the windows.h libraries, things would have been a lot easier. In this case though, the code was in some rarely used unit tests, and as such didn't need to be highly optimized, hence the creation, destruction and I/O operations of some text files wasn't an issue.