convert a string to integer in c++ without losing leading zeros - c++

hello i have a problem with converting a string of numbers to integer.
the problem is that using atoi() to convert the string to integer i loose the leading zeros.
can you please tell me a way to do that without loosing the leading zeros?
#include <fstream>
#include <iostream>
#include <iomanip>
#include <string>
using namespace std;
struct Book{
int id;
string title;
};
struct Author{
string firstName;
string lastName;
};
Author authorInfo[200];
Book bookInfo[200];
void load ( void )
{
int count = 0;
string temp;
ifstream fin;
fin.open("myfile.txt");
if (!fin.is_open())
{
cout << "Unable to open myfile.txt file\n";
exit(1);
}
while (fin.good())
{
getline(fin, temp, '#');
bookInfo[count].id = atoi(temp.c_str());
getline(fin, bookInfo[count].title, '#');
getline(fin, authorInfo[count].firstName, '#');
getline(fin, authorInfo[count].lastName, '#');
count++;
}
fin.close();
}

Ok, so I don't think you actually WANT to store the leading zeros. I think you want to DISPLAY a consistent number of digits in the output.
So, for example, to display a fixed size id with 5 digits [note that an id of 100000 will still display in 6 digits - all it does here is make sure it's always at least 5 digits, and fill it with '0' if the number is not big enough], we could do:
std::cout << std::setw(5) << std::setfill('0') << id << ...
Alternatively, as suggested in other answers, you don't want to use the ID in a form that is an integer, you could just store it as a string - unless you are going to do math on it, all that it changes is that it takes up a tiny bit more memory per book.

An integer does not have leading zeroes. Or perhaps, more correctly, it has between zero and an infinite number of them. The numbers 42, 042 and 000000042 (other than in the source code where a leading 0 indicates a different base) are all forty-two.
If you want to keep the leading zeroes, either leave it as a string or store more information somewhere as to how big the original string was. Something like this would be a good start:
#include <iostream>
#include <iomanip>
#include <cstring>
#include <cstdio>
#include <cstdlib>
int main (void) {
// Test data.
const char *sval = "0042";
// Get original size.
int size = strlen (sval);
// Convert to int (without leading 0s).
// strtol would be better for detecting bad numbers.
int ival = atoi (sval);
// Output details.
std::cout << sval << " has size of " << size << ".\n";
std::cout << "Integer value is " << ival << ".\n";
std::cout << "Recovered value is " << std::setw(size)
<< std::setfill('0') << ival << ".\n";
return 0;
}
which outputs:
0042 has size of 4.
Integer value is 42.
Recovered value is 0042.

A = strlen(string) returns the number of characters in your string (say number of digits comprehensive of leading zeros)
B = log10(atoi(string)) + 1 returns the number of digits in your number
A - B => number of leading zeros.
Now you can format those as you prefer.

There's no such thing as "leading zeros" in a number. "Leading zeros" is a property of a specific notation, like decimal ASCII representation of a number. Once you convert that notation to a conceptually abstract numerical representation, such metric as "number of leading zeros" is no longer applicable (at least in decimal terms). It is lost without a trace.
A number is a number. It doesn't have any "zeros", leading or otherwise.
The only thing you can do is to memorize how many leading zeros you had in the original notation (or how wide was the field), and then later, when you will convert the number back to decimal ASCII representation, re-create the proper number of leading zeros using that stored information.
BTW, in your case, when the input number represents a book ID with some pre-determined formatting (like leading zeros), you might consider a different approach: don't convert your book ID to int. Keep it as a string. It is not like you are going to have to perform arithmetic operations on book IDs, is it? Most likely all you'll need is relational and equality comparisons, which can be performed on strings.

I have encountered this type of problem last month!
I think you can use the Format() method provided by Class CString:
CString::Format() formats and stores a series of characters and values in the CString. Each optional argument (if any) is converted and output according to the corresponding format specification in pszFormat or from the string resource identified by nFormatID.
For example:
CString m_NodeName;
m_NodeName.Format(_T("%.4d"),Recv[2]*100+Recv[3]);
// %.4d means the argument will be formatted as an integer,
// 4 digits wide, with unused digits filled with leading zeroes
For the detail you can find here:
http://msdn.microsoft.com/zh-cn/library/18he3sk6(v=vs.100).aspx

If you need the leading zeros, then int is not the correct data type to use. In your case you may be better off just storing the original string.

There is no way of storing an int with leading 0s.
What you may want to do instead, is have a class do it for you:
class intWithLeadingZeros {
int number;
int numberOfLeadingZeros;
intWithLeadingZeros( string val )
{
// trivial code to break down string into zeros and number
}
string toString() {
// trivial code that concatenates leading 0s and number
}
};

Related

How to convert a string to given precision double?

Updated:
I have been trying all methods I could find in stackoverflow, and still could not find a solution.
My point is, I have a string "23.46" and would like to transfer it to double or float anyway. This is in order to be used in another library.
But no matter how I trancate,floor,*100,add,round, it always gives me 24.4600000001 or something like this.
I know there are some precision issue while transfer. But I do need a way to give me a number that double d = 24.46 precisely.
==============================================================================
I have many string values and some of them are double with converted precision as below:
char pt[100];
sprintf(pt, "%.2lf", i);
return string(pt);
Now on the other side of the code, I need to convert the strings back to double, but I tried strtod and atof with precision loss.
My questions are:
what is the good way to check if a string could be a double?
how to convert string back to double with given precision? I only need it to %.2lf be like:
0.21, 35.45, ...
Thanks so much!
Given that you say that using std::strtod is not giving you a solution to the problem, you can use stringstreams to parse strings as doubles, you can also use its flags to assert if the contents of the string are convertible.
Here is an example with some conversions back and forth, and with checks to see if the whole string (not just some digits in it), is parseable as double:
Live demo
#include <iostream>
#include <sstream>
#include <iomanip>
int main()
{
std::string str = "23.4k7"; //string with a character in the middle
std::istringstream ss(str); //put string in a stream
double num;
ss >> num; //convert string to double
if(!ss.fail() && ss.eof()) { //check if the whole string is parseable
std::cout << "is parseable" << std::endl;
}
else {
std::cout << "is not parseable";
return EXIT_FAILURE;
}
std::stringstream to_num;
to_num << std::fixed << std::setprecision(2) << num; //double to string 2 decimal places
std::cout << to_num.str();
to_num >> num; //final conversion to double
}
Since the string has an alphabetic character in it, this will output:
is not parseable
But if you use a valid number it will output the converted value:
string str:
234.2345
Output:
is parseable
234.23
Note that you could use
Live demo
if(ss >> num)
std::cout << "is parseable";
This, however, has a weakness, it will still parse if you have for instance 123.45rt56, 123.45 will be parsed, the rest will be discarded, the way it is in the sample code, if the string has any character, it will return an error. You can choose the more appropriate way for your needs.

How long double fits so many characters in just 12 bytes?

How long double fits so many characters in just 12 bytes?
I made an example, a C ++ factorial
when entering a large number, 1754 for example it calculates with a number that apparently would not fit a long double type.
#include <iostream>
#include <string.h>
using namespace std;
int main()
{
unsigned int n;
long double fatorial = 1;
cout << "Enter number: ";
cin >> n;
for(int i = 1; i <=n; ++i)
{
fatorial *= i;
}
string s = to_string(fatorial);
cout << "Factorial of " << n << " = " <<fatorial << " = " << s;
return 0;
}
Important note:
GCC Compiler on Windows, by visual Studio long double behaves like a double
The problem is how is it stored or the to_string function?
std::to_string(factorial) will return a string containing the same result as std::sprintf(buf, "%Lf", value).
In turn, %Lf prints the entire integer part of a long double, a period and 6 decimal digits of the fractional part.
Since factorial is a very large number, you end up with a very long string.
However, note that this has nothing to do with long double. A simpler example with e.g. double is:
#include <iostream>
#include <string>
int main()
{
std::cout << std::to_string(1e300) << '\n';
return 0;
}
This will print:
10000000000000000525047602 [...300 decimal digits...] 540160.000000
The decimal digits are not exactly zero because the number is not exactly 1e300 but the closest to it that can be represented in the floating-point type.
It doesn't fit that many characters. Rather, to_string produces that many characters from the data.
Here is a toy program:
std::string my_to_string( bool b ) {
if (b)
return "This is a string that never ends, it goes on and on my friend, some people started typing it not knowing what it was, and now they still are typing it it just because this is the string that never ends, it goes on and on my friend, some people started typing it not knowing what it was, and now they still are typing it just because...";
else
return "no it isn't, I can see the end right ^ there";
}
bool stores exactly 1 bit of data. But the string it produces from calling my_to_string can be as long as you want.
double's to_string is like that. It generates far more characters than there is "information" in the double.
This is because it is encoded as a base 10 number on output. Inside the double, it is encoded as a combination of an unsigned number, a sign bit, and an exponential part.
The "value" is then roughly "1+number/2^constant", times +/- one for the sign, times "2^exponential part".
There are only a certain number of "bits of precision" in base 2; if you printed it in base 2 (or hex, or any power-of-2 base) the double would have a few non-zero digits, then a pile of 0s afterwards (or, if small, it would have 0.0000...000 then a handful of non-zero digits).
But when converted to base 10 there isn't a pile of zero digits in it.
Take 0b10000000 -- aka 2^8. This is 256 in base 10 -- it has no trailing 0s at all!
This is because floating point numbers only store an approximation of the actual value. If you look at the actual exact value of 1754! you'll see that your result becomes completely different after the first ~18 digits. The digits after that are just the result of writing (a multiple of) a large power of two in decimal.

setprecision() gives extra digits if they are zeroes

I've used setprecision(8), but when I count asin(1) it returns 0.017452406 (10 digits, not 8!) What can be done there?
In order to fix the problem with decimal digits you need to use std::fixed.
As explaned in C++ Reference
Sets the floatfield format flag for the str stream to fixed.
When floatfield is set to fixed, floating-point values are written using fixed-point notation: the value is represented with exactly as many digits in the decimal part as specified by the precision field (precision) and with no exponent part.
To answer your requirement from the comments: "I need to make number (both integer and decimal parts) to be displayed in max 8 digits." You could use an ostringstream.
#include <iostream>
#include <sstream>
#include <string>
#include <iomanip>
int main(){
std::ostringstream ss; // declare your string stream
ss << std::setprecision(16); // set a high precision to avoid rounding
// Insert your float to the string stream
float f = 0.123456789;
ss << f;
// Get the string from the stream
std::string f_str = ss.str();
// Print
std::cout << f_str.substr(0, 8 + 1) << std::endl; // take 8 first digits
// Note the +1 here ^ (because of the dot)
return 0;
}
Output
0.1234567

Difference in bitset<10> and bitset<2>(input[i]) , need explanation

I just learned some simple encryption today and wrote a simple program to convert my text to 10-bit binary. Im not sure if i'm doing it correctly, but the commented section of the code and the actual code has 2 different 10-bit outputs. I am confused. Can someone explain it to me in layman terms?
#include <iostream>
#include <string>
#include <bitset>
#include "md5.h"
using namespace std;
using std::cout;
using std::endl;
int main(int argc, char *argv[])
{
string input ="";
cout << "Please enter a string:\n>";
getline(cin, input);
cout << "You entered: " << input << endl;
cout << "md5 of " << input << ": " << md5("input") << endl;
cout << "Binary is: ";
// cout << bitset<10>(input[1]);
for (int i=0; i<5; i++)
cout << bitset<2>(input[i]);
cout << endl;
return 0;
}
tl;dr : A char is 8 bits, and the string operator[] returns the different chars, as such you accessed different chars and took the first two bits of those. The solution comes in treating a char as exactly that: 8 bits. By doing some clever bit manipulation, we can achieve the desired effect.
The problem
While I still have not completely understood, what you were trying to do, I can answer what a problem could be with this code:
By calling
cout<<bitset<10>(input[1]);
you are reading the 10 bits starting from the second character ( input[0] would start from the first character).
Now, the loop does something entirely different:
for (int i=0; i<5; i++)
cout << bitset<2>(input[i]);
It uses the i-th character of the string and constructs a bitset from it.
The reference of the bitset constructor tells us this means the char is converted to an unsigned long long, which is then converted to a bitset.
Okay, so let's see how that works with a simple input string like
std::string input = "aaaaa";
The first character of this string is 'a', which gives you the 8 bits of '01100001' (ASCII table), and thus the 10 bit bitset that is constructed from that turns out to print
0001100001
where we see a clear padding for the bits to the left (more significant).
On the other hand, if you go through the characters with your loop, you access each character and take only 2 of the bits.
In our case of the character 'a'='01100001', these bits are '01'. So then your program would output 01 five times.
Now, the way to fix it is to actually think more about the bits you are actually accessing.
A possible solution
Do you want to get the first ten bits of the character string in any case?
In that case, you'd want to write something like:
std::bitset<10>(input[0]);
//Will pad the first two bits of the bitset as '0'
or
for(int i=0;i<5;++i){
char referenced = input[i/4];
std::bitset<2>((referenced>>(6-(i%4)*2)));
}
The loop code was redesigned to read the whole string sequentially into 2 bit bitsets.
So since in a char there are 8 bits, we can read 4 of those sets out of a single char -> that is the reason for the "referenced".
The bitshift in the lower part of the loop makes it so it starts with a shift of 6, then 4, then 2, then 0, and then resets to 6 for the next char, etc...
(That way, we can extract the 2 relevant bits out of each 8bit char)
This type of loop will actually read through all parts of your string and do the correct constructions.
A last remark
To construct a bitset directly from your string, you would have to use the raw memory in bits and from that construct the bitset.
You could construct 8 bit bitsets from each char and append those to each other, or create a string from each 8 bit bitset, concatenate those and then use the final string of 1 and 0 to construct a large bitset of arbitrary size.
I hope it helped.

C++ stringstream, if word is numeric, divide by two

I am fairly new to programming and have to create a program which reads the prompt: "I have 8 dollars to spend." It then needs to print out with each word on a separate line, and then if any of the strings is numeric, it needs to be divided by 2. Therefore it should end up printing out as:
I
have
4
dollars
to
spend.
I have managed to do everything, except finding the numeric value and dividing it by 2. So far I have this:
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main()
{
string prompt;
string word;
cout << "Prompt: ";
getline(cin, prompt);
stringstream ss;
ss.str(prompt);
while (ss >> word)
{
cout << word << endl;
}
return 0;
}
After looking through various other posts, I cannot manage to get this to work. I'm assuming its an if/else statement within the while loop along the lines of, if numeric, set int num to num / 2 then cout << num << endl;, else cout << word << endl;, but I can't figure it out.
Thanks in advance.
You can use the stringstream class, which handles conversions between strings and other data types, to attempt to convert a given string to a number. If the attempt is successful, you know
The stringstream object allows you to treat a string as though it is a stream similar to cin or cout.
Incorporate this into your while loop, like so:
while (ss >> word)
{
int value = 0;
stringstream convert(word); //create a _stringstream_ from a string
//if *word* (and therefore *convert*) contains a numeric value,
//it can be read into an _int_
if(convert >> value) { //this will be false if the data in *convert* is not numeric
cout << value / 2 << endl;
}
else
cout << word << endl;
}
The strtol (C++11 version that works on std::string directly: std::stol) function is really good for testing whether a string holds a number, and if so, what the numeric value is.
Or you could continue using iostreams like you have been... try extracting a number (int or double variable), and if that fails, clear the error bit and read a string.
I dont have 50 rep so I cant comment, thats why I'm writing it as answer.
I think you can check it character by character, using Ascii value of each char, & if there are ascii values representing numbers between two spaces(two \n in this case as you've already seperated each word), then you have to divide the number by 2.