fixed amount of digits on creating .txt file - c++

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

Related

Real input to FFTW

When I use FFTW, specifically the plan creation function fftw_plan_dft_r2c_1d(), for purely real input, the only "planner flag" (FFTW's terminology) which works is FFTW_ESTIMATE. Any of the others which I try, viz., FFTW_EXHAUSTIVE, FFTW_MEASURE, and FFTW_PATIENT, all generate an output file with all zeros.
I have tried changing the number of input data items from powers of 2 to otherwise. That makes no difference.
Scilab uses FFTW for its fft() and thus I am able to compare the output from my C++ program with the output from Scilab for the same input data file. When I use FFTW_ESTIMATE the two outputs match.
I have read the FFTW documentation. I cannot determine why the other planner flags do not work.
I am interested in using the FFTW_MEASURE planner flag since once the plan is formulated, I will want to use it repeatedly.
Below is my code. I have not included the fftw3.h file as I have not made any changes to it.
#pragma once
// FFT_05.h
//#include <array>
#include <cmath>
#include <complex>
#include <cstdint>
#include <fstream>
#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include "fftw3.h"
#define M_PI 3.14159265358979323846
// FFT_05_c.cpp
#include "FFT_05.h"
//*****************************************************************************
int32_t main(int argc, char* argv[]) {
std::fstream data_File;
std::string directory = "C:/Documents/Visual Studio 2022/Projects/";
directory += "FFT_05/Scilab programs/02/";
std::string file_Name = "Time_domain_input.txt";
data_File.open(directory + file_Name, std::ios_base::in | std::ios_base::binary);
double input_Value = 0.0;
int data_Count = 0;
if (data_File.is_open()) {
while (!data_File.eof()) {
data_File >> input_Value;
data_Count++;
}
}
std::cout << data_Count << std::endl;
data_File.seekg(0, std::ios_base::beg);
double* in;
fftw_complex* out;
fftw_plan p;
in = (double*)fftw_malloc(sizeof(double) * data_Count);
int data_Count_Out = (data_Count / 2) + 1;
out = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * data_Count_Out);
int i = 0;
while (!data_File.eof()) {
data_File >> input_Value;
in[i++] = input_Value;
}
data_File.close();
//for (int i = 0; i < data_Count; i++) {
// //std::cout << in[i][0] << ", " << in[i][1] << std::endl;
// std::cout << (i + 1) << ". " << in[i] << std::endl;
//}
//std::cout << "\n\n";
// FFTW procedure
p = fftw_plan_dft_r2c_1d(data_Count, in, out, FFTW_ESTIMATE);
if (!p) {
std::cout << "FFTW plan is NULL\n";
exit(1);
}
fftw_execute(p);
fftw_destroy_plan(p);
std::fstream FFT_Data_File;
FFT_Data_File.open(directory + "frequency_Domain_File_Name_c.txt",
std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
for (int i = 0; i < (data_Count_Out - 1); i++) {
FFT_Data_File << out[i][0] << " " << out[i][1] << std::endl;
}
FFT_Data_File << out[(data_Count_Out - 1)][0] << " " << out[(data_Count_Out - 1)][1];
FFT_Data_File.close();
fftw_free(in);
fftw_free(out);
}

std::stof() rounds numbers, how to avoid

Im trying to get a float value from a file.txt into a string. When I output that value with std::stof(str) it gets rounded. Example, in the text file there's "101471.71", whet i use the std::stof(str) it returns "101472", how to I avoid this?
Here's a part of that code (some parts are in spanish, sorry :p):
double CaptureLine(std::string filepath, int fileline, int linesize)
{
std::fstream file;
std::string n_str, num_n;
int current_line = 0, n_size, filesize = FileSize(filepath);
char ch_n;
double n_float = 0.0;
int n_line = filesize - fileline;
file.open("registros.txt");
if (file.is_open()) {
while (!file.eof()) {
current_line++;
std::getline(file, n_str);
if (current_line == n_line) break;
}
if (current_line < n_line) {
std::cout << "Error" << std::endl;
return 1;
}
file.close();
}
n_size = n_str.length();
for (int i = linesize; i < n_size; i++) {
ch_n = n_str.at(i);
num_n.push_back(ch_n);
}
std::cout << ">>" << num_n << "<<\n";
n_float = std::stof(num_n); //Here's the error
return n_float;
}
The issue probably isn't with std::stof, but is probably with the default precision of 6 in std::cout. You can use std::setprecision to increase that precision and capture all of your digits.
Here's a program that demonstrates:
#include <iostream>
#include <iomanip>
#include <string>
int main() {
std::cout << 101471.71f << "\n";
std::cout << std::stof("101471.71") << "\n";
std::cout << std::setprecision(8) << 101471.71f << "\n";
std::cout << std::stof("101471.71") << "\n";
return 0;
}
Outputs:
101472
101472
101471.71
101471.71
Be aware that std::setprecision sticks to the std::cout stream after it's called. Notice how the above example calls it exactly once but its effect sticks around.

Naming a log file using date and time in C++

So, I want to create a log file for an app I am trying to create and I don't know how to name the log to something like "log/date&time"
Anyway, here is my code:
#include <iostream>
#include <fstream>
#include <time.h>
#include <stdio.h>
#include <sstream>
using namespace std;
int main (int argc, char *argv[])
{
time_t t = time(0);
struct tm * now = localtime( & t );
char buffer [80];
strftime (buffer,80,"%Y-%m-%d.",now); //i think i can't just put "log/%Y-%m-%d." there.
ofstream myfile;
myfile.open ("log/" + buffer); // this is my problem, i can't put the ' "log/" + ' part there
if(myfile.is_open())
{
cout<<"Success"<<std::endl;
}
return 0;
}
You should use std::string which supports concatenation via the overloaded operator+.
std::string buffer(80, '\0');
strftime( &buffer[0], buffer.size(), "some format string", now);
/* ... */
std::ofstream myfile( ("log/" + buffer).c_str() );
// Remove the (..).c_str() part when working with a C++11 conforming
// standard library implementation
you actual question is "why doesnt this work"
myfile.open ("log/" + buffer);
answer - because c++ doesnt support what you want - concatenate a string literal with a char * and return another char *.
do
std::string filetime(buffer);
std::string filename = "log/" + filetime;
open(filename.c_str());
Consider using std:: facilities instead (std::string and std::ostringstream come to mind):
std::ostream& time_digits(std::ostream& out, unsigned int digits)
{ // convenience function: apply width and fill for the next input
return out << std::setw(digits) << std::setfill('0');
}
std::string unique_log_name()
{ // generate unique log name, depending on local time
// example output: "log/2014-04-19.log"
auto now = time(0);
tm *ltm = localtime(&now);
std::ostringstream buffer;
buffer
<< "log/" << time_digits(4) << ltm.tm_year
<< "-" << time_digits(2) << ltm.tm_mon
<< "-" << time_digits(2) << ltm.tm_day;
// could also add these to the name format:
// buffer
// << "-" << time_digits(2) << ltm.dm_hour
// << "-" << time_digits(2) << ltm.tm_min
// << "-" << time_digits(2) << ltm.tm_sec;
buffer << ".log"; // add extension
return buffer.str();
}
void client_code()
{ // construct log stream on unique file name
ofstream myfile{ unique_log_name() };
if(myfile)
{
cout << "Success" << std::endl;
}
}

creating files, checking if another one with the same name exists

Code(main.cpp) (C++):
#include <string>
#include <sstream>
#include <stdio.h>
#include <stdlib.h>
#include <ctime>
//general vars
std::ofstream ofs;
std::ifstream ifs;
std::stringstream ss;
//spamFiles vars
std::string defPath;
int defAmt;
void spamFiles(std::string paramPath);
int main(int argc, const char * argv[])
{
srand(time_t(NULL));
std::cout << "Enter the amount of files: ";
std::cin >> ::defAmt;
std::cout << "Now enter the target path: ";
std::cin >> ::defPath;
::spamFiles(::defPath);
std::cout << defAmt << " files were created." << std::endl;
return 0;
}
void spamFiles (std::string paramPath){
//system("open -a Terminal .");
for(int i = 0; i < ::defAmt; i++){
std::string tempS;
int ranNum = rand() % 501;
ss << ranNum;
std::string ssResult = ss.str();
std::string finalPath = ::defPath + ssResult + ".txt";
ifs.open(finalPath);
if(ifs.good()){
finalPath += "dupe.txt";
while(ifs.good()){
finalPath += "dupe.txt";
ifs.open(finalPath);
}
}
ofs.open(finalPath);
ofs << "";
ofs.close();
ss.str(std::string());
}
return;
}
My problem is following.
Whenever I run this and enter, lets say 53 as for the amount, in the end it'll never create the full amount of files. It's always scaled.
Here's an example.
Defined Amont: 300 -> What I Get: 240
Defined Amount: 20 -> What I get: 15
Defined Amount: 600 -> What I get: 450
Thanks in advance.
Based on the logic of your code, you are creating a file if your ifstream object is not 'good()'. If some files aren't being created, then the error lies here.
With some digging, you'll find that the constructor for an ifstream object does not take a string, but instead a char *.
Adding a c_str() to your 'finalPath' variable should take care of this issue.
Some things to note:
You've forgotten to include fstream and iostream.
When digging into problems like this, don't use random numbers as your first test case. It was easier for me to replicate your issue by just trying to create files in numerical order.
Also don't forget 'close()' your ifstreams!
My adaptation of the code:
#include <string>
#include <sstream>
#include <stdio.h>
#include <stdlib.h>
#include <ctime>
#include <fstream>
#include <iostream>
//general vars
std::ofstream ofs;
std::ifstream ifs;
std::stringstream ss;
//spamFiles vars
std::string defPath;
int defAmt;
void spamFiles(std::string paramPath);
int main(int argc, const char * argv[])
{
srand(time_t(NULL));
std::cout << "Enter the amount of files: ";
std::cin >> ::defAmt;
std::cout << "Now enter the target path: ";
std::cin >> ::defPath;
::spamFiles(::defPath);
std::cout << defAmt << " files were created." << std::endl;
return 0;
}
void spamFiles (std::string paramPath){
//system("open -a Terminal .");
for(int i = 0; i < ::defAmt; i++){
std::string tempS;
int ranNum = rand() % 501;
ss << ranNum;
std::string ssResult = ss.str();
std::string finalPath = ::defPath + ssResult + ".txt";
ifs.open(finalPath.c_str());
while(ifs.good()){
finalPath += "dupe.txt";
ifs.open(finalPath.c_str());
}
ifs.close();
std::cout << finalPath << std::endl;
ofs.open(finalPath.c_str());
ofs << "";
ofs.close();
ss.str(std::string());
}
return;
}

c++ double to string shows floating points

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++ .