The code I have written is as follows:
#include<stdio.h>
#include<math.h>
#include<string.h>
int strToint(char []);
int main()
{
char str[20];
printf("Enter the string-");
gets(str);
printf("\nthe integer is %d ",strToint(str));
return 0;
}
int strToint(char str[])
{
int i,a,sum=0,k,j;
a=strlen(str);
for(i=0;i<a;i++)
{
k=str[i]-'0';
j=pow(10,a-i-1);
sum+=k*j;
}
return sum;
}
If I enter the input as, say 567, I get 562 but I do not see why. I feel this is probably related to the pow function.
Help is appreciated. Thanks!
pow() is a floating point function and its behaviour varies from system to system. There's no requirement placed by the standard on its accuracy. It seems that yours is not returning values with the accuracy that you would require.
You do not need to implement functions to convert text to integer since the standard library contains functions that do that. An obvious choice would be sscanf.
But if you must implement such a function, you should use integer arithmetic. Any such code should handle negative values, and check for invalid input. For instance. What happens when you pass "a" to your function?
I tested your code and got the expected result. Maybe the problem is related with function pow.
You could write the function simpler without using functions that deal with real numbers.
For example
int strToint( const char str[] )
{
int sum = 0;
for ( ; *str; ++str )
{
sum = 10 * sum + *str - '0';
}
return sum;
}
Take into account that function gets is unsafe. It is better to use function fgets. For example
fgets( str, 20, stdin );
size_t n = strlen( str );
if ( str[n - 1] == '\n' ) str[n - 1] = '\0';
On the first call to pow(10,2) the library's weak pow() returns 99.999... which is truncated to 99 on assignment to j.
Since the first digit is 5, the final sum is 5 less. (100*5 vs 99*5)
If code must use FP functions, best to round before integer assignment
j = round(pow(10,...));
As #Vlad points out, all FP math can be avoided.
--
Floating point functions are not required by C to be accurate. A good pow() function though should have provided an exact answer here, that is why it worked on so many other machines.
For a complete atoi, there are many posts, such as FromStringToInteger
Related
I have written an atof() implementation in c . I am facing rounding off errors in this implementation . So , putting in a test value of 1236.965 gives a result of 1236.964966 but the library atof() function reurns 1236.965000 . My question is , how to make the user defined atof() implementation more 'correct' ?
Can the library definition of atof() be found somewhere ?
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
float str_to_float(char *);
void float_to_str(float,char *);
int main(){
int max_size;
float x;
char *arr;
printf("Enter max size of string : ");
scanf("%d",&max_size);
arr=malloc((max_size+1)*sizeof(char));
scanf("%s",arr);
x=str_to_float(arr);
printf("%f\n%f",x,atof(arr));
return 0;
}
float str_to_float(char *arr){
int i,j,flag;
float val;
char c;
i=0;
j=0;
val=0;
flag=0;
while ((c = *(arr+i))!='\0'){
// if ((c<'0')||(c>'9')) return 0;
if (c!='.'){
val =(val*10)+(c-'0');
if (flag == 1){
--j;
}
}
if (c=='.'){ if (flag == 1) return 0; flag=1;}
++i;
}
val = val*pow(10,j);
return val;
}
Change all your floats to doubles. When I tested it, that gave the same result as the library function atof for your test case.
atof returns double, not float. Remember that it actually is double and not float that is the "normal" floating-point type in C. A floating-point literal, such as 3.14, is of type double, and library functions such as sin, log and (the perhaps deceptively named) atof work with doubles.
It will still not be "precise", though. The closest you can get to 1236.965 as a float is (exactly) 1236.9649658203125, and as a double 1236.964999999999918145476840436458587646484375, which will be rounded to 1236.965000 by printf. No matter how many bits you have in a binary floating-point number, 1236.965 can't be exactly represented, similar to how 1/3 can't be exactly represented with a finite number of decimal digits: 0.3333333333333333...
And also, as seen in the discussion in comments, this is a hard problem, with many possible pitfalls if you want code that will always give the closest value.
I used your code as inspiration to write my own.
What other commenters and answers do not recognize is that the original reason for the question is an embedded situation. In my case the library "atof" pulls in something that does "printf" which pulls in "systemcalls" which I don't have.
So.... here I present a simple (does not implement exponential notation) atof implementation that works in floats, and is suitable for embedding.
My implementation uses way less variables.
float ratof(char *arr)
{
float val = 0;
int afterdot=0;
float scale=1;
int neg = 0;
if (*arr == '-') {
arr++;
neg = 1;
}
while (*arr) {
if (afterdot) {
scale = scale/10;
val = val + (*arr-'0')*scale;
} else {
if (*arr == '.')
afterdot++;
else
val = val * 10.0 + (*arr - '0');
}
arr++;
}
if(neg) return -val;
else return val;
}
how to make the user defined atof() implementation more 'correct' ?
Easy: 1) never overflow intermediate calculation and 2) only round once (at the end).
It is hard to do those 2 steps.
Note: C's atof(), strtof(), etc. also handle exponential notation - in decimal and hex.
Potential roundings
val*10
(val*10)+(c-'0');
pow(10,j)
val*pow(10,j) // This last multiplication is the only tolerable one.
Potential overflow (even though the final answer is within range)
val*10
(val*10)+(c-'0');
pow(10,j)
Using a wider type like double can greatly lessen the occurrence of such problems and achieve OP's "more 'correct'". Yet they still exist.
This is not an easy problem to solved to get the best (correct) floating point result from all string inputs.
Sample approaches to solve.
Avoid overflow: rather than pow(10,j):
val = val*pow(5,j); // rounds, `pow(5,j)` not expected to overflow a finite final result.
val = val*pow(2,j); // Does not round except at extremes
Code should form (ival*10)+(c-'0') using extended integer math in the loop for exactness.
Yet this is just scratching the surface of the many corner cases.
#Eric Postpischil commented on a robust C++ code that handles non-exponential notation string input well. It does initial math using integers and only rounds later in the process. This linked code is not visible unless your rep is 10,000+ as the question was deleted.
I'm new to c and trying to write a console application that takes the time signature and BPM information from a user's musical project and returns the length of one bar in seconds.
I want to take the user input string for time signature (example: "4/4"), isolate the first character (a numeral representing the number of beats per bar), and transform it into an integer to be used in the calculation.
The two methods I've tried,
int beatsPerBar = timeSignature[0];
and
int beatsPerBar = atoi(timeSignature[0])
both return the same error: "subscripted value is neither array nor pointer nor vector".
How do I correctly change the variable type of this character?
EDIT:
Using #R-Sahu 's suggestion. The code below compiles and builds with no errors or warnings.
#include <stdio.h>
#include <stdlib.h>
int main()
{
char timeSignature[4];
int BPM;
printf("Enter the working time signature of your project:");
scanf("%s",&timeSignature[4]);
int beatsPerBar = timeSignature[0]-'1';
printf("Enter the beats per minute:");
scanf("%i",&BPM);
printf("%i\n", beatsPerBar);
return 0;
}
However, when I test the code with the following values
timeSignature = "4/4"
BPM = 180
I get a resulting integer of -47 (calculator check says it should be returning 45).
What am I doing wrong? Clearly my understanding of encoding and the integers used to represent character values isn't where it should be. Can anyone share links to broad tutorials on this subject?
Use of
int beatsPerBar = atoi(timeSignature[0])
should result in a compiler error. The input argument type of atoi is char const*, which timeSignature[0] is not.
int beatsPerBar = timeSignature[0];
is syntactically right but not semantically. That will set the value of beatsPerBar to the integer value used to represent the character 4. If your platform uses ASCII encoding, that value is 52.
You should use:
int beatsPerBar = timeSignature[0] - '0';
to get the number 4 assigned to beatsPerBar.
If you want to be more careful, which you should, you can add the following check.
int beatsPerBar = 0;
if ( isdigit(timeSignature[0]) )
{
beatsPerBar = timeSignature[0] - '0';
}
else
{
// Deal with error.
}
As #r-sahu said:
The input argument type of atoi is const char *
So if you still want to use atoi you can convert the char to a string then use atoi as follows (for example):
if (isdigit(timeSignature[0]))
char dig[2]= {timeSignature[0],'\0'};
int beatsPerBar = atoi(dig);
No need to use atoi, you can simply convert a char to int. For instance
int beatsPerBar = timeSignature[0] - '0';
I am looking for a way to take a string and check 3 possibilities.
Digit and thus converts it to a signed int (not a long)
Is a symbolic representation previously defined at runtime, and converts it to a signed int
Neither
The "symbolic representation" will be basically like an associative array that starts at 0 elements and expands as more symbols are added. For example lets say for instance that C had associative arrays (I wish) with this peusdocode:
symbol_array['q'] = 3;
symbol_array['five'] = 5;
symbol_array['negfive'] = -5;
symbol_array['random294'] = 28;
signed int i;
string = get_from_input();
if(!(i = convert_to_int(string))) {
if(!(i = translate_from_symbol(string))) {
printf("Invalid symbol or integer\n");
exit(1);
}
}
printf("Your number: %d\n, i);
The idea being if they entered "5" it would convert it to 5 via convert_to_int, and if they entered "five" it would convert it to 5 via translate_from_symbol. As what I feel may be hardest is if they entered "random294" it wouldn't convert it to 294, but to 28. If they entered "foo" then it would exit(1).
My general questions are these: (Instead of making multiple posts)
When making convert_to_int I know I shouldn't use atoi because it doesn't fail right. Some people say to use strtol but it seems tedious to convert it back to a non-long int. The simplistic (read: shortest) way I've found is using sscanf:
int i;
if ((sscanf(string, "%d", &i)) == 1){
return i;
}
However, some people look down on that even. What is a better method if not sscanf or converting strtol?
Secondly, how can I not only return an integer but also know if it found one. For example if the user entered "0" then it would return 0, thus setting off my FALSE in my if statement. I had considered using -1 if not found but since I am returning signed int's then this also suffers from the same problem. In PHP I know for example with strpos they use === FALSE
Finally, is there any short code that emulates associate arrays and/or lets me push elements on to the array in runtime?
First, you might want to revise your syntax and set the keyword apart from the operand, i.e. "neg five" instead of "negfive". Otherwise your symbol lookup for the keywords has to consider every prefix. ("random294" might be okay if your keywords aren't allowed to have digits in them.)
Sure, sscanf tells you whether you found a decimal in the return value and writes that decimal to a separate int, which is nice, but you'll have to watch out for trailing characters by checking that the number of characters read equals the length of your string with the %n format. Otherwise, sscanf will consider 5x as legal decimal number. strtol also returns a pointer to the location after the parsed decimal number, but it relies too much on checking err for my taste.
The fact that strtol uses long integers shouldn't be an issue. If the input doesn't fit into an int, return INT_MAX or INT_MIN or issue an error.
You can also easily write a wrapper function around sscanf or strtol that suits your needs better. (I know I'd like a function that returns true on success and stores the integer via a pointer argument, sscanf style, where success means: no trailing non-digit characters.)
Finally, about the associative arrays: There is no short code, at least not in C. You'll have to implement your own hash map or use a library. As a first draft, I'd use a linear list of strings and check them one by one. This is a very naive approach, but easy to implement. I assume that you don't start out with a lot of symbols, and you're not doing a lot of checks, so speed shouldn't be an issue. (You can sort the array and use binary search to speed it up, but you'd have to re-sort after every insertion.) Once you have the logic of your program working, you can start thinking about hash maps.
Something like this should do your job:
#include <stdio.h>
#include <string.h>
struct StringToLongLookUp {
char *str;
char *num;
};
struct StringToLongLookUp table[] =
{
{ "q" , "3" },
{ "five" , "5" },
{ "negfive" , "-5" },
{ "random294", "28" }
};
int translate_from_symbol(char **str)
{
int i;
for(i = 0; i < (sizeof(table) / sizeof(struct StringToLongLookUp)); i++)
{
if(strcmp(*str, table[i].str) == 0)
{
*str = table[i].num;
return 1; // TRUE
}
}
return 0; // FALSE
}
int main()
{
char buf[100];
char *in = buf;
char *out;
int val;
scanf("%s", in);
translate_from_symbol(&in);
val = strtol(in, &out, 10);
if (in != out)
{
printf("\nValue = %d\n", val);
}
else
{
printf("\nValue Invalid\n");
}
}
Of course, you get a long, but converting that to int shouldn't be an issue as mentioned above.
I have made a program which converts numbers entered into a string into an integer like atoi does, but its giving wrong output.
#include<stdio.h>
#include<conio.h>
#include<math.h>
#include<string.h>
void main(void)
{
static int sum;
int i,x,y,z;
char string[10];
printf("Enter a string:\n");
gets(string);
x=strlen(string);
for(i=0; ;i++)
{
if(string[i]=='\0')
{
break;
}
y=pow(10,i);
z=string[x-i+1]*y;
sum+=z;
}
printf("%d",sum);
getch();
}
Ok. Here is a quick review of your code. Comments embedded.
#include<stdio.h>
Leave a space between #include and <stdio.h>.
#include<conio.h>
This is a non-standard Windows-only header that you don't need. Don't include this.
#include<math.h>
#include<string.h>
Again use a space, when including your headers.
void main(void)
While this is legal, it is more common to find the signature int main(int argc, char* argv[]) as the signature for the main function. I would suggest that you use that signature.
{
static int sum;
Why are you making this static? Are you planning to invoke main repeatedly and have the previous result for sum persist from one invocation of main to another? If not, then don't make it static.
int i,x,y,z;
char string[10];
Consider allocating more space for your string. Ten characters is quite small. Also consider creating a variable to represent the size of your string, rather than using a magic number, since you will likely have to reference the buffer size in multiple places.
printf("Enter a string:\n");
gets(string);
No. Don't do that!!! The function gets is a major security vulnerability!. It makes your program susceptible to buffer overflow attacks. Instead, use fgets, and specify the size of the buffer that you want to fill, so that it doesn't overrun your buffer. You should never, ever use plain gets.
x=strlen(string);
Consider choosing a more descriptive name for x. Perhaps len. It is perfectly ok (and good) to create variables that have identifiers longer than a single letter.
for(i=0; ;i++)
{
if(string[i]=='\0')
{
break;
}
Consider putting the termination condition in the for-loop; for(i = 0; string[i]!='\0'; i++).
y=pow(10,i);
z=string[x-i+1]*y;
Hint: there is a smarter way to do this than using pow.
sum+=z;
}
printf("%d",sum);
Ok. The above is fine, although you might want to use "%d\n".
getch();
You really shouldn't be doing this on all systems. Instead, do:
#ifdef _WIN32
system("pause");
#endif
If possible, though, I would suggest you avoid that weird pausing behavior. Suppose your professor uses an automated script to validate the output of your program. Putting any sort of pause in the program (even on Windows), will break such a script. If you don't want the terminal window to disappear while on Windows, you should invoke your program from the command prompt.
}
If you were to change the signature to something returning int as I suggested, then you would want to add the statement return 0; before the end of the function.
Your string do not contain the int values 0, 1, 2, ... 9.
They contain the char values '0', '1', '2', ... '9'. Encoded in e.g. ASCII, '0' == 48.
You need to convert the char to int; one way to do this is by subtracting '0', e.g.:
z = (string[x-i+1] - '0') * y;
Related questions
Please explain what this code is doing (someChar - 48)
How to convert a single char into an int
Language showdown: Convert string of digits to array of integers?
Many examples of digit conversion, using subtraction with both '0' and 48!
On Horner's Scheme
You can also do better by not using the pow, by using Horner scheme.
Here's an example (here ^ denotes exponentiation instead of bitwise-xor):
8675309 = 8*10^6 + 6*10^5 + 7*10^4 + 5*10^3 + 3*10^2 + 0*10^1 + 9*10^0
= (((((8*10 + 6)*10 + 7)*10 + 5)*10 + 3)*10 + 0)*10 + 9
It may look complicated at first, but it really isn't. You basically read the digits left to right, and you multiply your result so far by 10 before adding the next digit.
In table form:
step result digit result*10+digit
1 init=0 8 8
2 8 6 86
3 86 7 867
4 867 5 8675
5 8675 3 86753
6 86753 0 867530
7 867530 9 8675309=final
I'll leave you to implement this simple algorithm on your own, since this is homework.
See also
Wikipedia/Horner Scheme
Related questions
What does the ^ operator do in Java?
it should be:
z=(string[x-(i+1)]-'0')*y;
I made a program to find if a number belongs to fibonacci series or not and if it does whats its position.Whenever i type a number the if Condition goes wrong.
#include<stdio.h>
#include<conio.h>
#include<math.h>
void main(void)
{
int i,x=1,y=1,z,num;
clrscr();
printf("Enter a number to find in fibonacci series:");
scanf("%d",&num);
/*to find if the number is a part of fibonacci series or not*/
if((isdigit(sqrt(5*num*num+4)))||(isdigit(sqrt(5*num*num-4)))) //<-- this if!
{//belongs to fibo!
for(i=1; ;i++)
{
if(x==num)
break;
z=x+y;
x=y;
y=z;
}
printf("%d is the %d term of fibonacci series.",num,i);
}
else
printf("Dear user,The entered number is not a part of the fibonacci series.");
getch();
}
You're misunderstanding the isDigit function.
isDigit takes an ASCII character code and returns true if it represents a decimal digit.
You want to check whether the double returned by sqrt is an integer.
There's an obvious error in your use of isdigit(). That function (usually macro) is used to tell if a character is one of the characters 0..9 - certainly your code is dealing with numbers consistently and there's no need for character checking.
You'll want to take a closer look at what you're trying to accomplish. You're welcome to ask us which C functions might be suitable.
EDIT:
Ah, you want to know if that funky expression is an integer value. Alas, there's no built-in function for that. I haven't tested this, but I'd write
double a = (funky expr);
if (a == rint(a)) ...
... where rint() is a function that returns the double that's the nearest integer value to the given argument.
Why are you using isdigit? The result of sqrt is a double - you need to check that value directly.
You want to check if 5 * num * num + 4 or 5 * num * num - 4 is a perfect square. A function that will do this is:
int is_perfect_sq(double d)
{
double sqroot = rint(sqrt(d));
return (sqroot * sqroot) == d;
}
Note - this is a good disproof of the notion that you should never compare floating point numbers for equality. In this case, it is fine, since a "perfect square" must be an integer.