Scanf-reading variables which have to meet ceratin specifications - c++

I have to solve an exercise which at first glance seemed really simple to me. However, I am not so sure how to solve it. Given the fact that variables a and b have certain admissable values, should I verify whether they are in the correct range after reading them? And regarding variable b, in the examples it is given in scientific notation, so should I read it using the e specifier? And last but not least, the assignment supression of ',' is done using "%*[,]"?
Write a set of statements to read from the standard input three variables a, b and c, where the variables have the following types:
a – unsigned short integer, b – float, c – string of at most 31 characters
The input values are separated by one comma. The first variable is given as an octal number. The admissible values for a and b are as follows:
-4331 < a <= 28731
-1035 < b < 9749273
Suitable error messages should be given if the values are not within the allowed range or in the wrong format. Sample input:
12745, -1.e-3, Is this a good one?
0xEE04F, 21e75, Maybe this one...
70073, 21e+6, Or this one. Could this string be too long to put into allocated area?

OP: should I verify whether they are in the correct range after reading them?
A: Yes. The scanning will check gross range error. Then code checks local range.
OP: read it using the e specifier?
A: a, e, f, g are all equivalent in scanf() family. So use what seems appropriate: e is good.
OP: the assignment suppression of ',' is done using "%*[,]"
A: Almost: One could use "%*1[,]", but "," is sufficient.
Use fgets() and sscanf() and then check range.
char buf[1000];
if (fgets(buf, sizeof buf, stdin) == NULL) {
handle_EOF_or_IOError();
}
short Number;
float x;
char s[31+1];
if (3 != sscanf(buf, "%ho,%e, %31[^\n]", &Number, &x, s)) {
handle_ParseError();
}
short NumberTooSmall = -4331;
short NumberMax = 28731
float xTooSmall = -1035.0f;
float xTooBig = 9749273.0f;
if ((Number <= NumberTooSmall) || (Number > NumberMax) ||
(x <= xTooSmall) || (x >= xTooBig)) {
handle_RangeError();
}
Note: there is a subtle issue on when the parsed string begin in "12745, -1.e-3, Is this a good one?", etc. OP says that , is the seperator. This implies the string starts with " Is this ...". I think the OP wants to skip leading spaces and get "Is this ...".
Assuming IEEE binary32 for float, 9749273.0 needs 24 bits to represent exactly. Since this format has 23+1 bits of precision for normal numbers, all is well. Care should be observed with range testing of floating point values.

Related

Number changing value when assigned to variable?

I have a little problem when assigning a result to a variable, this is happening the first time to me now. I call Convert() with "aaa" as a parameter, here is my output:
aaa
**676** *(value from cout)* = 26^(3-1)*1 **675** *(value of the variable)*
+26 = 26^(3-2)*1 700
+1 = 26^(3-3)*1 701
701
And here the code:
string alphabet="abcdefghijklmnopqrstuvwxyz";
unsigned long long Convert(string &str){
unsigned long long wvalue=0;
for(int i=0;i<str.size();++i){
size_t found=alphabet.find(str[i]);
if(found==string::npos)
cout<<"Please enter only lowercase letters of the english alphabet!"<<endl;
unsigned long long add=((found+1)*pow(26,(str.size()-(i+1))));
wvalue+=add;
if(i>0)cout<<"+";
cout<<"\t"<<((found+1)*pow(26,(str.size()-(i+1))))<<" = "<<"26^("<<str.size()<<"-"<<(i+1) <<")*"<<(found+1)<<"\t"<<wvalue<<endl;
}
return wvalue;
}
Chances are I'm missing something awfully obvious, but I cannot figure it out.
((found+1)*pow(26,(str.size()-(i+1))))
is doing the calculation, and it is doing as it is supposed to, the result within the cout-statment is correct. But the variable is substracted by 1 in the first two assignments.
pow is a floating-point function. It takes and returns floating point numbers. Assigning a floating-point number to an integer variable truncates it to an integer number, so it might have been 675.9999999 just before the assignment, which will turn into 675 when assigned to the integer variable add.
cout also rounds floating-point numbers, depending on the configuration for example to 6 significant digits. 676.0 is a better approximation than 675.999, so you see 676 in the output.
Since you don't want to calculate with real numbers but only with integral numbers, you better stay with integral functions. To take 26 to the power of n, better use multiplication n times. Since you already use a loop, and like to have the next power of 26 for every character, the best is to add a variable in which you keep the current power value, like this:
unsigned long long currentFactor = 1;
for (...) {
...
unsigned long long add = currentFactor * (found+1);
wvalue += add;
currentFactor *= 26;
}
Also note that you don't have to find the character in an alphabet string. You can also just use character arithmetic to do this:
int charNumber(char c) {
if (c >= 'a' && c <= 'z')
return c - 'a'; // calculate the position of c relative to 'a'
else
return -1; // error
}

c++ how to get "one digit exponent" with printf

Is there a way to print in scientific notation less than 3 places for exponent part of number?
The 6.1 formatting doesn't affect exponent but only the number part:
var=1.23e-9;
printf ("%e\n", var);
printf ("%6.1e\n", var);
gives
1.230000e-009
1.2e-009
I've also tried this in wxWidgets with formatting of string but the behavior is the same.
m_var->SetLabel(wxString::Format(wxT("%6.1e"),var));
What I'd like to have is 1.2e-9.
According to Wikipedia:
The exponent always contains at least two digits; if the value is
zero, the exponent is 00. In Windows, the exponent contains three
digits by default, e.g. 1.5e002, but this can be altered by
Microsoft-specific _set_output_format function.
_set_output_format
I've had to do this a lot (I write file parsers and some file formats like NITF require you to store numeric values as strings).
What you do is an exploit based on what base-10 math (scientific notation) really means: It means that for all real numbers y, y = (x) * 10^(N) for some integer N and some x in the range (-1, 1) exclusive.
So, you do the following
void PrintScientific(double d)
{
int exponent = (int)floor(log10( fabs(d))); // This will round down the exponent
double base = d * pow(10, -1.0*exponent);
printf("%lfE%+01d", base, exponent);
}
You can add all the format specifiers you need to control the # of chars before, after the "." decimal place.
Do NOT forget the rounding step! This is how it works, using the properties of base10 and logarithms (base 10 here):
Let y = x * 10^N =>
log(y) = log(x*10^N) =>
log(y) = log(x) + log(10^N) => // From Log "product" rule
log(y) = log(x) + N
Since x is in the range (-10, 10) -"()" means exclusive(exclusive), that implies log(x) is in the range (-1, 1). So when we round down for integer conversion, we're dropping "log(x)" contribution.
You can then get the "x" portion from the original number, which lets you output the original in any scientific notation you want to use.
With standard C printf() this can't be done (and the use of three digits by default seems wrong as well), at least in C99 (I don't have a newer version at hand). The relevant quote from the C99 standard is at 7.19.6.1 paragraph 8, formats e,f:
.... The exponent always contains at least two digits, and only as many more digits as necessary to represent the exponent. If the value is zero, the exponent is zero. ...
The best bet to fit this [portably] into code using lots of these outputs is to use C++ IOStreams: although the default formatting is the same as in C, it is possible to install a custom facet into the stream's std::locale which does the formatting the way you need. That said, writing the formatting code might not be entirely trivial. Although I would probably just built on the standard conversion and then remove the excess zeros after the e character.
I found Zach's answer to be the fastest and simplest method and is also applicable to any OS. I did find that two modifications were needed on the "base =" line for it to work for all numbers. (Otherwise nan's when exponent is negative in cygwin). The extra print statement is just for patran neutral file compatibility. I would have upvoted his answer, but I just started on stackexchange so I don't have sufficient "reputation".
void PrintScientific(double d)
{
int exponent = (int)floor(log10( fabs(d))); // This will round down the exponent
double base = (d * pow(10.0, -1*exponent));
if(abs(exponent)<10)
printf("%13.9lfE%+01d", base, exponent);
else
printf("%12.9lfE%+01d", base, exponent);
}
C/C++ specifies at least two exponent digits with printf("%e",...). To print only 1, and to deal with Visual Studio which, by default, prints at least 3, additional code is needed.
Consider IOStreams #Dietmar Kühl
If C++ code still wants to use printf() style formats:
Adjusting the value of a double before calling printf() too often results in rounding issues, range shorting and general corner case failures like dealing with log10(0.0). Also consider large double just near a power-of-10 where log10() may come up short, -0.0, INF, NAN.
In this case, better to post-process the string.
double var = 1.23e-9;
// - 1 . x e - EEEEE \0
#define ExpectedSize (1+1+1+1+1+1+ 5 + 1)
char buf[ExpectedSize + 10];
snprintf(buf, sizeof buf, "%.1e", var);
char *e = strchr(buf, 'e'); // lucky 'e' not in "Infinity" nor "NaN"
if (e) {
e++;
int expo = atoi(e);
snprintf(e, sizeof buf - (e - buf), "%1d", expo);
}
printf("'%6s'\n", buf); // '1.2e-9'
Note: %e is amiable to post-processing as its width is not so unwieldy as "%f". sprintf(buf, "%f", DBL_MAX) could be 1000s of char.

string to float conversion?

I'm wondering what sort of algorithm could be used to take something like "4.72" into a float data type, equal to
float x = 4.72;
scanf, operator>> for istreams, and strtof would be the obvious choices.
There is also atof, but, like atoi, it lacks a way to tell you there was an error in the input, so it's generally best to avoid both.
For C++ you can use boost::lexical_cast:
std::string str( "4.72" );
float x = boost::lexical_cast< float >( str );
For C you can use sscanf:
char str[]= "4.72";
float x;
sscanf( str, "%f", &x );
For C++ This is the algorithm I use:
bool FromString(const string& str, double& number) {
std::istringstream i(str);
if (!(i >> number)) {
// Number conversion failed
return false;
}
return true;
}
I used atof() in the past for the conversion, but I found this problematic because if no valid conversion can be made, it will return (0.0). So, you would not know if it failed and returned zero, or if the string actually had "0" in it.
For C strtod() and C99 friends strtof() and strtold() (description on same link) already have that algorithm implemented.
If you are having problems writing your own, post your code and specific questions about it.
As you've asked for an algorithm, not a method, here is my explanation for a simple algorithm (and an implementation in C):
Initialize 4 integer variables, one for the value before dot, one for the after part, one for the power of the mantissa, one for the sign. Let's say, f, m, d, sign = 1.
First look for + or - sign at the beginning. If there are no sign characters or + sign then continue. If the first character is -, then sign = -1.
Then, read an integer value into f until a . or NULL character.
If you end up with a dot character, then start reading the mantissa part as in the previous step into m. But this time also multiply d by 10 with each digit.
In the end, return sign*(f + (float) m/d). The casting makes sure the division is done in floating-points and the type of the expression is float.
I guess, reading the code might be easier. So here is the code:
float atof(char *s)
{
int f, m, sign, d=1;
f = m = 0;
sign = (s[0] == '-') ? -1 : 1;
if (s[0] == '-' || s[0] == '+') s++;
for (; *s != '.' && *s; s++) {
f = (*s-'0') + f*10;
}
if (*s == '.')
for (++s; *s; s++) {
m = (*s-'0') + m*10;
d *= 10;
}
return sign*(f + (float)m/d);
}
You can use boost:lexical_cast
http://www.boost.org/doc/libs/1_44_0/libs/conversion/lexical_cast.htm
I assume you want an actual algorithm, not a library function that already does it. I don't have time to write and test actual code, but here is what I would do:
Initialize a float that will be used as an accumulator to 0.
Figure out where the decimal place is in the string, this will let you know what "column" each of the digits is (i.e. 100s, 10s, 1s, 1/10ths, etc).
Start at the beginning of the string.
Take that digit, convert to an int (trivially done by subtracting 0x30 from the ASCII value)
Multiply the value by the place column (for the first digit in your example, that would be 4 * 1 == 4, for the next digit 7 * 0.1 == 0.7).
Add the result to the accumulator
Repeat from step 4 for each remaining digit.
The accumulator now contains your result.
Due to the roundoff of converting between base 10 and base 2 in every iteration of this loop, the result you get from this algorithm may not be the closest possible binary representation to the original value. I don't really know of a good way to improve it though... perhaps someone else can chime in with that.
The atof() function can be helpful.
http://www.cplusplus.com/reference/clibrary/cstdlib/atof/
From cplusplus.com: "stringstream provides an interface to manipulate strings as if they were input/output streams."
You can initialize a stringstream with your string then read a float from the stringstream using operator>> just like you would with cin.
Here is an example:
#include<iostream>
#include<string>
#include<sstream>
using namespace std;
int main() {
string s = "4.72";
stringstream sstrm(s);
float x;
sstrm >> x;
cout << x << endl;
}

How to convert string (22.123) format number into float variable format without using any API in c++

How to convert string (22.123) format number into float variable format without using any API in c++. This is just to understand more about the inside coding.. thnx
something like:
double string_to_double(std::string s)
{
int p = 0;
int p_dec = s.length();
double val = 0;
for (int i=0; i<s.length(); ++i)
{
double digit = (double)(s[i] - '0');
if (s[i] == '.') { p_dec = p; }
else { val += digit*powf(10,p--); }
}
val /= powf(10, p_dec);
}
Basic algorithm, assuming no input in the form 1.2e-4:
(1) Read an integer before the dot. If the number of digits is > 16 (normal precision of double), convert that integer into floating point directly and return.
(2) Read an at most 16 digits dot as an integer. Compute (that integer) ÷ 10digits read. Sum up this with the integer in step (1) and return.
This only involve 2 floating point operation: one + and one ÷, and a bunch of integer arithmetics. The advantage over multiplications and divisions by powers of 10 is that the error won't accumulate unnecessarily.
(To read 16-digit integers you need a 64-bit int.)
In reality, you should use sscanf(str, "%lf", ...), std::istringstream, or boost::lexical_cast<double>.
go over the number digit by digit by using a bunch of multiplications and divisions by powers of 10 and construct the string character by character.
If you just want an idea of how to do it, the other answer, if you want an accurate result, the problem is not so simple and you should refer to the literature on the subject. An example: ftp://ftp.ccs.neu.edu/pub/people/will/howtoread.ps
I'm pretty sure that the Plauger Standard C Library book has a disc with the source of strtod.
http://www.amazon.co.uk/Standard-C-Library-P-J-Plauger/dp/0131315099
and there are online versions too:
http://www.google.co.uk/search?hl=en&client=firefox-a&hs=IvI&rls=org.mozilla%3Aen-GB%3Aofficial&q=strtod+source+code

C++: Big Integers

I am a writing a lexer as part of a compiler project and I need to detect if an integer is larger than what can fit in a int so I can print an error. Is there a C++ standard library for big integers that could fit this purpose?
The Standard C library functions for converting number strings to integers are supposed to detect numbers which are out of range, and set errno to ERANGE to indicate the problem. See here
You could probably use libgmp. However, I think for your purpose, it's just unnecessary.
If you, for example, parse your numbers to 32-bit unsigned int, you
parse the first at most 9 decimal numbers (that's floor(32*log(2)/log(10)). If you haven't more, the number is OK.
take the next digit. If the number you got / 10 is not equal to the number from the previous step, the number is bad.
if you have more digits (eg. more than 9+1), the number is bad.
else the number is good.
Be sure to skip any leading zeros etc.
libgmp is a general solution, though maybe a bit heavyweight.
For a lighter-weight lexical analyzer, you could treat it as a string; trim leading zeros, then if it's longer than 10 digits, it's too long; if shorter then it's OK, if exactly 10 digits, string compare to the max values 2^31=2147483648 or 2^32=4294967296. Keep in mind that -2^31 is a legal value but 2^31 isn't. Also keep in mind the syntax for octal and hexadecimal constants.
To everyone suggesting atoi:
My atoi() implementation does not set errno.
My atoi() implementation does not return INT_MIN or INT_MAX on overflow.
We cannot rely on sign reversal. Consider 0x4000...0.
*2 and the negative bit is set.
*4 and the value is zero.
With base-10 numbers our next digit would multiply this by 10.
This is all nuts. Unless your lexer is parsing gigs of numerical data, stop the premature optimization already. It only leads to grief.
This approach may be inefficient, but it's adequate for your needs:
const char * p = "1234567890123";
int i = atoi( p );
ostringstream o;
o << i;
return o.str() == p;
Or, leveraging the stack:
const char * p = "1234567890123";
int i = atoi( p );
char buffer [ 12 ];
snprintf( buffer, 12, "%d", i );
return strcmp(buffer,p) == 0;
How about this. Use atol, and check for overflow and underflow.
#include <iostream>
#include <string>
using namespace std;
main()
{
string str;
cin >> str;
int i = atol(str.c_str());
if (i == INT_MIN && str != "-2147483648") {
cout << "Underflow" << endl;
} else if (i == INT_MAX && str != "2147483647") {
cout << "Overflow" << endl;
} else {
cout << "In range" << endl;
}
}
You might want to check out GMP if you want to be able to deal with such numbers.
In your lexer as you parse the integer string you must multiply by 10 before you add each new digit (assuming you're parsing from left to right). If that running total suddenly becomes negative, you've exceeded the precision of the integer.
If your language (like C) supports compile-time evaluation of expressions, then you might need to think about that, too.
Stuff like this:
#define N 2147483643 // This is 2^31-5, i.e. close to the limit.
int toobig = N + N;
GCC will catch this, saying "warning: integer overflow in expression", but of course no individual literal is overflowing. This might be more than you require, just thought I'd point it out as stuff that real compilers to in this department.
You can check to see if the number is higher or lower than INT_MAX or INT_MIN respectively. You would need to #include <limits.h>