Rounding converting from string to double/float - c++

I am trying to extract a number from a string and convert it into a double or float so I can do some numerical operations on it. I am able to isolate the variable I need so the string consists only of the number, but when I try to convert it to a float or double it rounds the value, ie from 160430.6 to 160431.
//Helper Function to Extract Value of Interest
//Based on column of final digit of numbers being same across various FLOPS output files
double findValue(string &line, int &refN){
setprecision(100);
string output;
//go to end column and work backwards to get value string
while(line[refN] != ' '){
output = line[refN] + output;
refN = refN - 1;
}
const char* outputx = output.c_str();
double out = atof(outputx);
//removing the const char* line and replacing atof with stod(output) runs into the same issue
return out;
}
int main()
{
string name;
cin >> name;
ifstream file(name);
//opens file
if(!file.is_open()){"error while opening the file";
}else{
//Temporary Reference Definitions
string ref = "TOGW";
int refN = 25;
string line = findLine(file,ref);
double MTOGW = findValue(line, refN);
cout << MTOGW;
}
return 0;
}
I initially tried using stof() to convert, but that rounded. I have also tried using stod() and stold(), and last tried converting to a const char* and using atof(). I have messed with the setprecision() value, but also have not been able to solve it that way.
I cannot use Boost

You were almost there. The rounding was occurring on output, so that's where you need to use setprecision. That and always use double instead of float to ensure you have enough precision in your variables.
#include <vector>
#include <ranges>
#include <iomanip>
#include <iostream>
#include <string>
using std::string;
double findValue(string &line, int &refN){
//setprecision(100);
string output;
//go to end column and work backwards to get value string
while(line[refN] != ' '){
output = line[refN] + output;
refN = refN - 1;
}
const char* outputx = output.c_str();
double out = strtod(outputx, NULL);
return out;
}
int main()
{
string s = " 160430.6";
int n = s.size() - 1;
std::cout << std::setprecision(10) << findValue(s, n) << '\n';
}
See it in action on the Godbolt compiler.

Related

How to replace "pi" by "3.14"?

How to replace all "pi" from a string by "3.14"? Example: INPUT = "xpix" ___ OUTPUT = "x3.14x" for a string, not character array.
This doesn't work:
#include<iostream>
using namespace std;
void replacePi(string str)
{
if(str.size() <=1)
return ;
replacePi(str.substr(1));
int l = str.length();
if(str[0]=='p' && str[1]=='i')
{
for(int i=l;i>1;i--)
str[i+2] = str[i];
str[0] = '3';
str[1] = '.';
str[2] = '1';
str[3] = '4';
}
}
int main()
{
string s;
cin>>s;
replacePi(s);
cout << s << endl;
}
There is a ready to use function in the C++ lib. It is called: std::regex_replace. You can read the documentation in the CPP Reference here.
Since it uses regexes it is very powerful. The disadvantage is that it may be a little bit too slow during runtime for some uses case. But for your example, this does not matter.
So, a common C++ solution would be:
#include <iostream>
#include <string>
#include <regex>
int main() {
// The test string
std::string input{ "Pi is a magical number. Pi is used in many places. Go for Pi" };
// Use simply the replace function
std::string output = std::regex_replace(input, std::regex("Pi"), "3.14");
// Show the output
std::cout << output << "\n";
}
But my guess is that you are learning C++ and the teacher gave you a task and expects a solution without using elements from the std C++ library. So, a hands on solution.
This can be implemented best with a temporary string. You check character by character from the original string. If the characters do not belong to Pi, then copy them as is to new new string. Else, copy 3.14 to the new string.
At the end, overwrite the original string with the temp string.
Example:
#include <iostream>
#include <string>
using namespace std;
void replacePi(string& str) {
// Our temporay
string temp = "";
// Sanity check
if (str.length() > 1) {
// Iterate over all chararcters in the source string
for (size_t i = 0; i < str.length() - 1; ++i) {
// Check for Pi in source string
if (str[i] == 'P' and str[i + 1] == 'i') {
// Add replacement string to temp
temp += "3.14";
// We consumed two characters, P and i, so increase index one more time
++i;
}
else {
// Take over normal character
temp += str[i];
}
}
str = temp;
}
}
// Test code
int main() {
// The test string
std::string str{ "Pi is a magical number. Pi is used in many places. Go for Pi" };
// Do the replacement
replacePi(str);
// Show result
std::cout << str << '\n';
}
What you need is string::find and string::replace. Here is an example
size_t replace_all(std::string& str, std::string from, std::string to)
{
size_t count = 0;
std::string::size_type pos;
while((pos=str.find(from)) != str.npos)
{
str.replace(pos, from.length(), to);
count++;
}
return count;
}
void replacePi(std::string& str)
{
replace_all(str, "pi", "3.14");
}

i am trying to use getline to read a csv file line by line and separate the data in the file and turn a string into int

I am a beginner and I just need a bit of help on why I getline is showing an error:
this is what I have so far
#include <iostream>
#include <iomanip>
#include <cmath>
#include <fstream>
using namespace std;
const double TAX_RATE = 0.0825;
const int MAX_ITEMS = 1000;
const int MAX_TRANSACTIONS = 100;
int main(int argc, char const *argv[]){
string fname = "";
int itemCnt = 0, start = 0, end = 0;
int ids[MAX_ITEMS], qtys[MAX_ITEMS];
double costs[MAX_ITEMS], subtotals[MAX_TRANSACTIONS],
taxes[MAX_TRANSACTIONS], totals[MAX_TRANSACTIONS];
string names[MAX_ITEMS], paymentTypes[MAX_ITEMS], payments[MAX_ITEMS];
ifstream iFile;
if ( argc != 2 ) {
cout<<"usage: "<< argv[0]<< " <file name>" <<endl;
return 0;
} else {
iFile.open(argv[1]);
}
if (!iFile) {
cout<<"Error: Invalid file name"<<endl;
cin.clear();
}
while (!iFile.eof())
{
getline(iFile,str); //this isn't working
int commaLoc = str.find(',');
ids[itemCnt]= str.substr(0,commaLoc);
str = str.substr(commaLoc +1, str.length());
//string to int I'm not sure how to do I know its something with stoi() but not sure how to format it
}
return 0;
}
I am able to get the file to open but I'm not sure why getline isn't working it keeps saying something like
no instance of overload function
My csv file looks like:
1,Laptop,799.99,1,cash,1100
I need it to read the first number and because Its a string i don't know how to save it as an int
Multiple errors. First there is nothing called 'str' in your program. I will guess its just a string used as a temp buffer
do not do this (!File.eof) it doesnt do what you think.
while (iFile)
{
string str; <<<<<==== added
getline(iFile,str); //this isn't working <<<===is now
int commaLoc = str.find(',');
Next this line doesnt work because ids are ints and substring returns a string.
// ids[itemCnt]= str.substr(0,commaLoc);
ids[itemCnt]= stoi(str.substr(0,commaLoc)); <<<<==== fixed
str = str.substr(commaLoc +1, str.length());
}
I strongly recommend you use std::vector instead of c-style fixed size arrays. Takes 5 minutes to learn how to use them and they have huge benefits. If you must use fixed size arrays use std::array instead of c-style
You can read a string and try to convert it to a number in different ways. For example, since C++17, you can use from_chars. One of its overloads:
Receives a pair of begin and end char pointers, and an int variable,
tries to parse an int number, and
and returns the parsed number, together with a pointer to the first character that wasn't part of the match.
int i{};
auto [ptr, ec] = std::from_chars(str.data(), str.data() + str.size(), i);
if (ec == std::errc{}) { /* do something with i */} else { /* error */ }
[Demo]
Full code (using a istrinstream instead of a ifstream):
#include <charconv> // from_chars
#include <iomanip>
#include <iostream>
#include <sstream> // istringstream
#include <system_error> // errc
constinit const int MAX_ITEMS = 10;
int main() {
std::istringstream iss{
"1,Laptop,799.99,1,cash,1100\n"
"2,PC,688.88,2,card,1101\n"
"blah,Keyboard,39.00,3,cash,1102"
};
size_t itemCnt{};
int ids[MAX_ITEMS]{};
std::string str{};
while (std::getline(iss, str)) {
// Parse counter
int i{};
auto [ptr, ec] = std::from_chars(str.data(), str.data() + str.size(), i);
if (ec == std::errc{}) {
ids[itemCnt] = i;
// Remaining string
std::string remaining_string{ str.substr(ptr - str.data() + 1) };
std::cout << ids[itemCnt] << ", " << remaining_string << "\n";
}
else {
std::cout << "Error: invalid counter.\n";
}
++itemCnt;
}
}
// Outputs:
//
// 1, Laptop,799.99,1,cash,1100
// 2, PC,688.88,2,card,1101
// Error: invalid counter.

Addition string to avoid number limitation

I want to add two numbers by adding number by number like when you are child.
In order to calculate very long numbers (more than the C++ limitation).
My first step is to try an example 2 numbers having a sum < 10:
string valeur1 = "135";
string valeur2 = "844";
string result;
for (int i = 0; i < valeur1.length(); i++)
{
std::ostringstream ss;
int value;
int value3;
int value2;
//string to int
valeur1[i] >> value;
valeur2[i] >> value2;
value3 = (value + value2);
// int to string
ss << value3;
result = result + ss.str();
}
cout << result;
Am I headed in the right direction?
I think you are headed in the right direction. Three things you can improve:
You have to take into account when value3 is larger than 10 (You seem aware of that)
Be careful when the two numbers don't have the same number of digits. Now your code will fail in that case.
You are using an array of characters. Why not use an array of integers instead? If you only want to avoid the size limitation of an integer I think it would be a much better option as you wouldn't need all the string<->integer conversions.
Your first step is very simple:
#include <string>
#include <iostream>
int main()
{
std::string s1 = "135";
std::string s2 = "844";
std::string result;
for(size_t i=0;i<std::min(s1.size(),s2.size());i++)
result+= std::to_string(s1[i]-'0'+s2[i]-'0');
std::cout<<result<<std::endl;
return 0;
}
Edit:
As noted Gerard Abello , you should take into account the different size of strings and case when sum is greater than 3. However,I believe that the string representation is a good option. One of the options for adding the numbers as strings.
# include <string>
# include <iostream>
std::pair<int,std::string> simpleConvert(const std::string &str);
std::string add(const std::string &first,const std::string &second);
int main()
{
std::string s1 = "128";
std::string s2 = "9999";
std::string result = add(s1,s2);
std::cout<<result<<std::endl;
return 0;
}
std::pair<int,std::string> simpleConvert(const std::string &str)
{
if(str.size()==1)
return std::make_pair(0,str);
else if(str.size()==2)
return std::make_pair(str[0]-'0',std::string(str.begin()+1,str.end()));
}
std::string add(const std::string &first,const std::string &second)
{
std::string s1(first.rbegin(),first.rend());
std::string s2(second.rbegin(),second.rend());
auto n = s1.size();
auto m = s2.size();
auto min = std::min(n,m);
auto max = std::max(n,m);
for(size_t j=min;j!=max;j++)
if(n<m)
s1+="0";
else
s2+="0";
std::string result;
int add=0;
for(size_t i=0;i<s1.size();i++)
{
auto temp = simpleConvert(std::to_string(s1[i]-'0'+s2[i]-'0'+add));
result+= temp.second;
add = temp.first;
}
if(add!=0)
result+=std::to_string(add);
return std::string(result.rbegin(),result.rend());
}

C++ SDL 2.0 - Importing multiple textures using a loop

I don't know whether or not this is possible but I have used this technique in different languages but am struggling to use it in C++. I have 10 images that I am trying to load into an array using a loop as so:
for (int i = 0; i < 10; i++)
{
Sprite[i] = IMG_LoadTexture(renderer, "Graphics/Player" + i + ".png");
}
This however does not seem to work in C++ so I was wondering what I am doing wrong, or what can I do to get the same result without having to load each image individually like so:
Sprite[0] = IMG_LoadTexture(renderer, "Graphics/Player0.png");
My error is: "Expression must have integral or unscoped enum type"
Thanks for any help =)
You cannot do this:
"This is my number: " + (int)4 + "!";
This is illegal. It will give you an error for trying to operator+ a const char* and a const char[SOME_INT_GOES_HERE] or another error for trying to use operator+ to add an int onto a string. Things just don't work that way.
You'd either have to use C (i.e. snprintf()) or a string stream. Here's my test code for isolating your problem:
#include <iostream>
#include <string>
int main()
{
int a = 1;
std::string str = "blah";
std::string end = "!";
//std::string hello = str + a + end;// GIVES AN ERROR for operator+
std::string hello = "blah" + a + "!";
//const char* c_str = "blah" + a + "end";
//std::cout << c_str << std::endl;
std::cout << hello << std::endl;
return 0;
}
Here's an alternative solution using string streams.
#include <iostream>
#include <string>
#include <sstream>
int main()
{
int i = 0;
std::string str;
std::stringstream ss;
while (i < 10)
{
//Send text to string stream.
ss << "text" << i;
//Set string to the text inside string stream
str = ss.str();
//Print out the string
std::cout << str << std::endl;
//ss.clear() doesn't work. Calling a constructor
//for std::string() and setting ss.str(std::string())
//will set the string stream to an empty string.
ss.str(std::string());
//Remember to increment the variable inside of while{}
++i;
}
}
Alternatively, you can also use std::to_string() if you're using C++11 (which just requires -std=c++11) but std::to_string() is broken on some sets of compilers (i.e. regular MinGW). Either switch to another flavor where it works (i.e. MinGW-w64) or just write your own to_string() function using string streams behind the scenes.
snprintf() may be the fastest way of doing such a thing, but for safer C++ and better style, it is recommended you use a non-C way of doing things.
I had a similar problem and I solwed it this way:
#include <iostream>
using namespace std;
int main() {
string line;
for (int i = 0; i < 10; i++) {
line = "Graphics/Player" + inttostr(i) + ".png"; //I wrote inttostr function because built in inttostr functions messed up my program (see below)
char charger[line.length()]; //creating char array
for (int i = 0; i < sizeof(line); i++) {
charger[i] = line[i]; // copying string to char arry
}
Sprite[i] = IMG_LoadTexture(renderer, charger);
}
}
string inttostr(int integer) { //I know it isn't the best way to convert integer to string, but it works
string charakter;
int swap;
bool negativ = false;
if (integer < 0) {
integer = -integer;
negativ = true;
}
if (integer == 0) {
charakter = "0";
}
while (integer >= 1) {
swap = integer % 10;
integer = integer / 10;
charakter = char(swap + 48) + charakter;
}
if (negativ) {
charakter = "-" + charakter;
}
return charakter;
}

C++ Parse string to integer with specific classes

It might sound stupid, but I was just wondering how can I parse a string to an integer in C++?
This is for a school project, and the explanation sheet says :
"Only the use of iostream and string classes and system() function is permitted; The use of any other class or function is prohibited."
I have searched around a bit, but the only suggestions I found are using classes like atoi or atof.
The input string is already checked for error before the parsing, so it will always only contain an integer.
I wouldn't mind doing the parsing manually with conditionals, but I don't think it would be my teacher's (or anyone's) preferred way.
Thanks a bunch if you can help.
So, you can use system(), huh? Behold this masterpiece of engineering:
#include <fstream>
void download_boost() {
system("wget http://downloads.sourceforge.net/"
"project/boost/boost/1.47.0/boost_1_47_0.tar.bz2"
"?r=http%3A%2F%2Fwww.boost.org%2Fusers%2Fhistory%2F"
"version_1_47_0.html&ts=1316116936&use_mirror=kent"
" -O boost_1_47_0.tar.bz2");
}
void unpack_boost() {
system("tar --bzip2 -xf boost_1_47_0.tar.bz2");
}
void write_program() {
std::ofstream os("blah.cpp");
os << "#include \"boost/lexical_cast.hpp\"\n"
"#include <iostream>\n"
"#include <string>\n"
"int main() { std::string s; std::cin >> s;"
"int i = boost::lexical_cast<int>(s);"
"std::cout << i; }";
}
void compile_program() {
system("g++ -Iboost_1_47_0 blah.cpp");
}
void run_program() {
system("./a.out");
}
int main() {
download_boost();
unpack_boost();
write_program();
compile_program();
run_program();
}
(I'm assuming a typical Linux installation with some common tools installed.)
#include <iostream>
#include <string>
int stringToInt(const std::string &text)
{
int number = 0;
int powerIndex = 1;
for (int i = text.length() - 1; i >= 0; i--)
{
number += powerIndex * (text.at(i) - '0');
powerIndex *= 10;
}
return number;
}
std::string intToString (int number)
{
std::string text = "";
int numberHolder = number;
while (numberHolder)
{
char digit = (numberHolder % 10) + '0';
text = digit + text;
numberHolder /= 10;
}
return text;
}
int main ()
{
//Testing...
int number = stringToInt("123");
std::string text = intToString(456);
std::cout << number << "\n" << text << "\n";
return 0;
}
stringstreams come closest to what you want to do, although it may seem a little cumbersome at first.
Example:
#include <string>
#include <sstream>
// (...)
std::string str = "12345";
std::istringstream ss(str);
int num;
ss >> num;
As a function (and optimized):
#include <sstream>
#include <string>
int stringToInt(const std::string &str) {
static std::istringstream ss;
ss.clear();
ss.str(str);
int num;
ss >> num;
return num;
}
Here, I am reusing the std::istringstream by applying the static keyword. I have created a very simple benchmark that demonstrates that this is approximately 2 times faster than not reusing: http://pastebin.com/vLSmCyMF
Warning regarding thread-safety: As рытфолд has noted in the comments, the above implementation of stringToInt is not thread-safe. If you want to call this function safely from multiple threads, you should use the thread_local storage class specifier (available since C++11).
std::string mystring = "12";
std::ostringstream str(mystring);
int someint;
str >> someint;
Basically, given a std::string mystring that contains only an integer:
Start with an int result = 0;.
While mystring has digits
Multiply result by ten
Add biggest digit (first in string)
Remember that the character '0' does not have the value of 0.
Remove the biggest digit from the string
So:
If I have the string "1543", result = 0
we multiply result by ten : result = 0
we add the first digit: result = 1
remove the first digit from the string "543"
we multiply result by ten : result = 10
we add the first digit: result = 15
remove the first digit from the string "43"
we multiply result by ten : result = 150
we add the first digit: result = 154
remove the first digit from the string "3"
we multiply result by ten : result = 1540
we add the first digit: result = 1543
remove the first digit from the string ""
string is empty, so we're done
I wrote code, but then remembered this was a homework problem.