How to select number format when writing to file

I'm modifying someone else's longer code for work, and I'm very new to C++. I have this section working, but I get only a single digit integer in the .txt file that contains the array values, and I need it to include three or four decimal places for each value as well.

I have a different version of this, for a different array, that was giving outputs with up to four digit integers, but those values actually had no decimals (they were channel numbers). So the way it is here, it seems that it will do multiple digits, but no decimal places, which I need for this particular one.

Thank you in advance for the help.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
  //File Write Section
  		ofstream fw("/home/silicon/Desktop/KPiX_Data/UO_CAL_SLOPE.txt", std::ofstream::out);
  			//check if file was successfully opened for writing
			if (fw.is_open())
			{
  				//store array contents to text file
  				for (int i = 0; i < 4096; i++) {
    				fw << UO_Slope[i][1] << "\n";
  				}
  			fw.close();
  			fw.clear();
			}
			else cout << "Problem with opening file";
			printf("File written to UO_CAL_SLOPE.txt");
What type is UO_Slope? What are some example values of UO_Slope[i][1]?

The default "precision" of C++ streams is 6, so if your data is being stored properly as floating-point values, something else is causing a problem.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Example program
#include <iostream>

int main()
{
  std::cout << 1.0 << '\n';
  std::cout << 1.1 << '\n';
  std::cout << 1.12 << '\n';
  std::cout << 1.123 << '\n';
  std::cout << 1.1234 << '\n';
  std::cout << 1.12345 << '\n';
  std::cout << 1.123456 << '\n';
  std::cout << 10.123456 << '\n';
}

1
1.1
1.12
1.123
1.1234
1.12345
1.12346
10.1235



PS: You don't need to write the second parameter on line 2 (std::ofstream::out). It's implied by the use ofstream.
Last edited on
Thank you for the response!

I believe it is a Double_t, from this line:
 
Double_t slope = grCalib->GetFunction("pol1")->GetParameter(1);


When I do this statement it does print on screen correctly with all the extra decimal places, but only after I added the %e. The person who helped get me started on this with the other arrays, which do contain only integers, had this same line, but with %d in place of the %e, and I changed it to get it to print on screen with all the decimal places I need, to see that that worked, and then I've been trying to get these values to write to a file instead of just to the screen.

1
2
3

printf("UO_Slope %e\n" ,UO_Slope[CAL_Index][1]);
Last edited on
What is Double_t defined/declared as?

(BTW, using “_t” as a suffix to types in your codebase is forbidden by POSIX, and may conflict with the compiler’s implementation of the C and C++ Standard Libraries.)

To clean up your code a little:

1
2
3
4
5
6
7
8
9
	std::ofstream f("/home/silicon/Desktop/KPiX_Data/UO_CAL_SLOPE.txt");

	for (int i = 0; i < 4096; i++)
	{
		f << UO_Slope[i][1] << "\n";
	}
	
	if (f) std::cout << "File written to UO_CAL_SLOPE.txt\n";
	else   std::cerr << "Failure to write UO_CAL_SLOPE.txt\n";

There are two things that can be improved:

  • use a variable (pass as argument to a function?) for the file name.
  • Do not hard-code the number of items in your array/vector/whatever.

If we were to create a function to do this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
bool write_slopes(
	const std::filesystem::path & filename,
	whatever_type_it_is UO_Slope,
	std::size_t num_items )
{
	std::ofstream f(filename);

	for (std::size_t i = 0;  i < num_items;  i++)
	{
		f << UO_Slope[i][1] << "\n";
	}
	
	if (f) std::cout << "File written to "  << filename.stem() << "\n";
	else   std::cerr << "Failure to write " << filename.stem() << "\n";

	return f;  // besides logging success or failure, also report it to the caller
}

I present the array and its size as arguments to the write function, but you are clearly using globals. You can certainly continue to do that instead of the arguments as I do. Just make sure to reference the actual size of the data instead of hard-coding it.

As already noted in other answers, the actual type of UO_slope[n][1] is important: it should be a floating point type (float, double, long double) or one that knows how to print itself as such. Otherwise it will not print properly.

(It is possible to goober all new streams such that they print wrong, but few people know how to do that and those that do won’t, because it is a dumb, dumb thing to do. Hence I think it unlikely this is your problem.)

Hope this helps.
Last edited on
I honestly am not sure where the variable 'slope' is defined in the other person's code if it is not this line:
 
Double_t slope = grCalib->GetFunction("pol1")->GetParameter(1);

It is this variable 'slope' that is filling the values in my array.

That's the first line 'slope' appears on in the code and after that is used in some math expressions as if it's a number something else is being divided by.

I defined the UO_Slope array myself as:
 
int UO_Slope [4096][1];

So maybe since I've defined my array this way, the value was saved in the array as int. It is this array that I'm trying to save to a file.

I can print it to the terminal screen this way:
 
printf("UO_Slope %e\n" ,UO_Slope[CAL_Index][1]);

And it does show up with the correct decimals (by using the %e\n), and looks like this: <UO_Slope 3.180364e+00> in the terminal window. But then my file writing code (as shown in my original post above) would save this as simply <3>. I need it to save the 3 and all the decimal places as well.

Thank you again for your time. I'm quite new to this and am guessing there are probably half a dozen or more other concepts I would need to understand first to entirely follow what's happening here.
Last edited on
The issue is that operator << is overloaded to select on the type. That is, there is one for char, and another for int, and for double, etc.

So whatever Double_t is is confusing the compiler.

...which means that the printf() is probably relying on some tricky (and therefore fragile) type promotion behavior the compiler is letting pass, and should not be trusted.
Crank your compiler warnings up to see if it complains.

If you want to see the actual type of Double_t, you can use a couple of tricks to compile a small file that will tell you.

  • method one: https://stackoverflow.com/a/56766138/2706707
  • method two: https://stackoverflow.com/a/14617848/2706707

Regardless of whether your UO_Slope array has a constants size, using magic numbers is code smell. Follow the ODR rule and declare it correctly. This will save you headache later:

1
2
3
constexpr std::size_t UO_SLOPE_MAX_SIZE = 4096;
int UO_Slope [UO_SLOPE_MAX_SIZE][1];
std::size_t UO_Slope_Size = 0;  // number of items in actual use in the array, in [0,4096). 

Then wherever you access the elements of UO_Slope you know how many elements are in actual use:

1
2
for (std::size_t n = 0;  n < UO_Slope_Size;  n += 1)
  do_something_with( UO_Slope[n][0] );


I notice that you have defined an array with a subdimension of length one. That is very odd, and is equivalent to declaring the array without the subdimension size.

What happens, then, is when you have code to access the second element of the subarray

    UO_Slope[n][1]
                ↑
           second element of zero-based array!

the compiler assumes that you the programmer knows what you are doing and does not check that you are making a fencepost error. The consequence is that you actually access the next item in the array: UO_Slope[n+1][0]!

The fencepost error causes:

  • the first element of the array (UO_Slope[0][0]) to never be accessed, and
  • a buffer overflow attempt to access one more element than the array possesses.

That second bullet is significant, because it is undefined behavior. You just haven’t been bitten hard enough to see your program crash. Yet. But you are certainly being bitten somewhere. You just haven’t noticed yet. (Probably.)

So, yeah, in C++ arrays index from zero.
only a single digit integer in the .txt file that contains the array values, and I need it to include three or four decimal places for each value as well.


As the type being inserted into the stream is of type int, why would you expect it to include decimal places?
Last edited on
the printf includes the decimals in the terminal, so I didn't understand it, but it seemed that the values were there in the variable int type.

Duthomhas above suggested that there might be deeper errors here, and it seems I found them. When I tried to change the array variable type to float or double, my program will compile, but then has an error while running. It looks like it's getting all the way to the last entry and then having a problem, so I think it might have something to do with how I've indexed my array, as was suggested.

I'll work on that and see if it clears things up.

Thank you for your time.
I can print it to the terminal screen this way:
printf("UO_Slope %e\n" ,UO_Slope[CAL_Index][1]);


Would using fprintf an option?

BTW what IDE do you use? When you hover with the mouse over Double_t does it show you anything?
Topic archived. No new replies allowed.