For faster integer input in c we can use http://abhisharlives.blogspot.in/2012/06/really-fast-io-methods-for-programming.html methods ,but how to take faster input of floating numbers in c?
Using ideas from the link you provided, I wrote up my own fast floating number input technique. Here's the code (including the main() to test it):
#include <stdio.h>
#define gc getchar_unlocked
int neg;
int scandigits(double *x, int div) {
register int c = gc();
register double pow10 = 1;
if ( x == NULL ) {
return -1;
}
*x = 0;
while ( (c < '0' || c > '9') && c != '-' ) {
c = gc();
}
if ( c == '-' ) {
neg = 1;
c = gc();
}
while ( !(c < '0' || c > '9') ) {
*x *= 10;
*x += (c - '0');
pow10 *= 10;
c = gc();
}
if ( neg )
*x = -*x;
if ( div )
*x /= pow10;
return c;
}
void scandouble(double *x) {
double left, right = 0;
if ( x == NULL ) {
return;
}
neg = 0;
int ret = scandigits(&left, 0);
if ( ret == '.' )
scandigits(&right, 1);
*x = left + right;
}
int main() {
double d;
scandouble(&d);
printf("%f", d);
return 0;
}
Note: In general, most competitive coding contests do NOT require fast IO. Instead, they require much better algorithms etc. However, in some very rare cases you require fast IO to eke out that last 0.01s to make your code get accepted. I would suggest using such trickery (that's what I call it) in only such cases.
Often using integer math is faster than double. The below uses integer math to compose the significand and optional exponent.
double getdouble(void) {
int ch = getchar();
int sign = ch;
if (sign == '-' || sign == '+') {
ch = getchar();
}
long long sum = 0;
int digit_count = 0;
int dp_offset = -1;
int power10 = 0;
int dp = '.';
for (;;) {
while (ch >= '0' && ch <= '9') {
digit_count++;
if (sum < LLONG_MAX / 10) {
sum = sum * 10 + ch - '0';
} else {
power10++;
}
ch = getchar();
}
if (ch == dp) {
dp = '0';
dp_offset = digit_count;
ch = getchar();
} else {
break;
}
}
if (dp_offset >= 0) {
power10 -= digit_count - dp_offset;
}
if (ch == 'e' || ch == 'E') {
ch = getchar();
int esign = ch;
if (esign == '-' || esign == '+') {
ch = getchar();
}
int expo = 0;
while (ch >= '0' && ch <= '9') {
expo = expo * 10 + ch - '0';
ch = getchar();
}
if (esign == '-') expo = -expo;
power10 += expo;
}
double y = sum;
if (power10) {
// combine these 2 steps for speed with `pow(10,power10)`.
// leave separate for better handling of very large/very tiny numbers
y *= pow(5, power10); //
y = ldexp(y, power10);
}
if (sign == '-') y = -y;
return y;
}
Same answer as atof() 86% of the time.
When in error, 1 bit error.
Worse case: 1 bit.
Handles exponential notation and sub-normals, -0.0.
Does not handle NAN, INF.
Returns INF on +/-DBL_MAX, works on all smaller values.
Related
I'm writing a function that can read integers expressed in hexadecimal.
This is my code. The main function should not be modified.
#include <stdio.h>
#include <ctype.h>
#define SIZE 100
main()
{
int array[SIZE], n;
int gethex(int*);
int i, sum;
for (n = 0; n < SIZE && gethex(&array[n]) != EOF; n++)
;
sum = 0;
for (i = 0; i < n; i++)
sum += array[i];
printf("The sum is %d\n", sum);
}
int gethex(int *pn)
{
int c, sign;
c = getchar();
while (isspace(c))
;
if (!isxdigit(c) && c != EOF && c != '+' && c != '-') {
ungetc(c, stdin);
return 0;
}
sign = (c == '-') ? -1 : 1;
if (c == '+' || c == '-')
c = getchar();
for (*pn = 0; isxdigit (c); c = getchar()) {
if (c >= '0' && c <= '9') {
*pn = 16 * *pn + (c - '0');
}
else if (c >= 'a' && c <= 'f') {
*pn = 16 * *pn + (c - 'a' + 10);
}
else if (c >= 'A' && c <= 'F') {
*pn = 16 * *pn + (c - 'A' + 10);
}
}
*pn *= sign;
if (c == EOF) {
*pn = c;
return c;
}
}
The result value should come out like this.
-FFec
10000
^Z
The sum is 20
However, my code outputs
The sum is 1717986860
What's wrong?
At least these problems:
Warnings not fully enabled
Warnings are not fully enabled, losing OP and others valuable time. #Jens
End of gethex() lacks a return value.
warning: control reaches end of non-void function [-Wreturn-type]
Infinite loop
Once a '\n is read, loop never ends. #Weather Vane
while (isspace(c))
;
Non hex input also set up an infinite loop with ungetc(c, stdin); as that same c will repeatedly get read on the next function call.
if (!isxdigit(c) && c != EOF && c != '+' && c != '-') {
ungetc(c, stdin);
return 0;
}
int overflow possible
Code like *pn = 16 * *pn + (c - '0'); and *pn *= sign; can lead to int overflow, which is undefined behavior (UB). Robust code would prevent that.
Some untested code to fix these issues.
// Return 0 if non-numeric input detected.
// Return 2 when input out of int range
// Return 1 on success
// Return EOF when input is only white-space, sign or none
int gethex(int *pn) {
int ch;
// Consume leading white-space
do {
ch = getchar();
} while (isspace(ch));
// Get sign, if any
int sign = ch; // remember 1st
if (ch == '-' || ch != '+') {
ch = getchar();
}
if (ch == EOF) {
return EOF;
}
if (!isxdigit(ch)) {
// Consume non-numeric input
return 0;
// Perhaps better to return EOF here to stop calling code.
}
int overflow = 0;
int sum = 0;
while (isxdigit(ch)) {
int digit = 0;
if (isdigit(ch)) {
digit = ch - '0';
} else if (isupper(ch)) {
digit = ch - 'A' + 10;
} else if (islower(ch)) {
digit = ch - 'a' + 10;
}
if (sum <= INT_MIN / 16
&& (sum < INT_MIN / 16 || digit > -(INT_MIN % 16))) {
overflow = 1;
sum = INT_MIN;
} else {
// Accumulate as a negative number as there are more
// negative vales than positive ones.
// This prevents bad code like -INT_MIN later.
sum = sum * 16 - digit;
}
}
if (sign != '-') {
if (sum < -INT_MAX) {
overflow = 1;
sum = INT_MAX;
} else {
sum = -sum;
}
}
*pn = sum;
ungetc(ch, stdin);
return overflow ? 2 : 1;
}
I tried to write a solution from exercise 2-3. After compilation, it returns random numbers on output. I don't really understand where this issue is coming from.
Any help appreciated.
StackOverflow keeps asking for more details. The purpose of the program is listed in the code bellow.
More delails.
Purpose of the code:
Write the function htoi(s), which converts a string of hexa-
decimal digits (including an optional 0x or 0X) into its
equivalent integer value. The allowable digits are 0 through 9,
a through f, and A through F.
/*
* Write the function htoi(s), which converts a string of hexa-
* decimal digits (including an optional 0x or 0X) into its
* equivalent integer value. The allowable digits are 0 through 9,
* a through f, and A through F.
*/
#include <stdio.h>
#include <math.h>
int hti(char s)
{
const char hexlist[] = "aAbBcCdDeEfF";
int answ = 0;
int i;
for (i=0; s != hexlist[i] && hexlist[i] != '\0'; i++)
;
if (hexlist[i] == '\0')
answ = 0;
else
answ = 10 + (i/2);
return answ;
}
unsigned int htoi(const char s[])
{
int answ;
int power = 0;
signed int i = 0;
int viable = 0;
int hexit;
if (s[i] == '0')
{
i++;
if (s[i] == 'x' || s[i] == 'X')
i++;
}
const int stop = i;
for (i; s[i] != '\0'; i++)
;
i--;
while (viable == 0 && i >= stop)
{
if (s[i] >= '0' && s[i] <= '9')
{
answ = answ + ((s[i] - '0') * pow(16, power));
}
else
{
hexit = hti(s[i]);
if (hexit == 0)
viable = 1;
else
{
hexit = hexit * (pow(16, power));
answ += hexit;
}
}
i--;
power++;
}
if (viable == 1)
return 0;
else
return answ;
}
int main()
{
char test[] = "AC";
int i = htoi(test);
printf("%d\n", i);
return 0;
}
answ is not initialized in htoi. Initialize it to zero.
My code should find hex numbers in a user input (followed or not by 0x), copy them in an array as a string and, every time it finds a non 1-9 a-f A-F character or EOF, it should execute the htoi function converting the characters in the string into a decimal number, proceeding from right to left and using a multiplier to account for the position. It doesn't do what it's supposed to do. It generates numbers that have nothing to do with the decimal equivalent of my hex numbers.
#include <stdio.h>
#include <string.h>
#include <math.h>
int htoi(char num[]);
int main()
{
int c,i = 0;
char num[1000];
while ((c = getchar()) != EOF)
{
if ((c > '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'a' && c <= 'f'))
{
num[i] = c;
i++;
}
else if (c == '0')
{
if ((c = getchar) == 'x' || c == 'X')
{
num[i] = '\0';
printf("%d", htoi(num));
i=0;
}
else
{
num[i] = c;
i++;
}
}
else
{
num[i] = '\0';
if (num[0] != '\0')
{
printf("%d", htoi(num));
}
i=0;
}
}
num[i] = '\0';
if (num[0] != '\0')
{
printf("%d", htoi(num));
}
i=0;
return 0;
}
int htoi(char num[])
{
int c,i, dig;
int dec;
int multiplier = 1;
for (i = strlen(num)-1; i >= 0; i--)
{
c = num[i];
if (c > '0' && c <= '9')
{
dig = c - '0';
}
else if (c > 'a' && c <= 'f')
{
dig = c - 'a' + 10;
}
else if (c > 'A' && c <= 'F')
{
dig = c - 'A' + 10;
}
dec = dec + dig * multiplier;
multiplier * 16;
return dec;
}
}
Three problems:
multiplier * 16; just throws away the result. You'd want multiplier *= 16
return dec returns immediately with the current value of dec. You should have that after the loop.
The variable dec is uninitialized, which means it will have an indeterminate value. Using it without initialization, like you do, will lead to undefined behavior.
There are other problems as well, some of which would have been caught by the compiler leading to errors or warnings. The three above was just what I found after a quick glance.
I need to know how to convert a user input, which is a string, to a double. like if he writes in the string "23.45", it converts into double 23.45
(without any library functions).
I already got this code for integer, but don't know how to continue with double:
#include <stdio.h>
void main()
{
char input[100];
printf("Type a String which will be converted to an Integer: ");
scanf("%s", input);
int number = 0;
int i = 0;
if (input[i] >= 48 && input[i] <= 57)
{
while (input[i] >= '0' && input[i] <= '9')
{
number = number * 10;
number = number + input[i] - '0';
i++;
}
printf("string %s -> number %d \n", input, number);
}
else
{
printf("Enter a number! \n");
}
}
There's probably no reason why you'd roll out your own version of this, as strtod in stdlib.h already covers all manner of formats.
Here's a version which covers signed numbers as input and has some hints of where more suitable error handling could be placed:
#include <stdbool.h>
static void halt_and_catch_fire (void);
double strtod_homebrewn (const char* str)
{
double result = 0;
// handle signs:
bool is_negative = false;
if(*str == '-')
{
is_negative = true;
str++;
}
else if(*str == '+')
{
str++;
}
// handle the dot position:
bool is_dot_found = false;
double multiplier = 0.1;
// the actual conversion:
for(const char* s=str; *s!='\0'; s++)
{
if(*s >= '0' && *s <= '9') // ctype.h isdigit() would be preferred here
{
if(is_dot_found)
{
result += (*s - '0') * multiplier;
multiplier /= 10;
}
else
{
result *= 10;
result += *s - '0';
}
}
else if(*s == '.')
{
if(is_dot_found) // two dots?
{
halt_and_catch_fire(); // replace this with error handling
}
is_dot_found = true;
}
else if(*s != '\0') // all cases tested, some weird unknown character found
{
halt_and_catch_fire(); // replace this with error handling
}
}
if(is_negative)
{
result = -result;
}
return result;
}
static void halt_and_catch_fire (void)
{
halt_and_catch_fire();
}
#include <stdio.h>
void main()
{
char input[100];
printf("Type a String which will be converted to a double: ");
scanf("%s", input);
double number = 0.0;
double divider = 1.0;
int inFraction = 0;
int i = 0;
if (input[i] >= 48 && input[i] <= 57)
{
inFraction = 0;
while ((input[i] >= '0' && input[i] <= '9') || input[i] == '.')
{
if (input[i] == '.')
{
i++;
inFraction = 1;
continue;
}
number = number * 10.0;
number = number + input[i] - '0';
i++;
if (inFraction) divider *= 10.0;
}
number /= divider;
printf("string %s -> number %g \n", input, number);
}
else
{
printf("Enter a number! \n");
}
}
Edit: As clux pointed out, this fails when the fraction starts with zeroes. Bummer. Anyway, perhaps someone conceives a simple fix? I can only think of adding a "readzeroes()" function and let that run after the dot.
You already have a function to read an int. Simply use that. Pseudo code:
float read_float()
{
float f = read_int()
if(next is dot) skipdot else return f;
float frac = read_int()
while (frac>1) frac /= 10
return f+frac;
}
Edit: only use this approach for small number of digits after the decimal point.
Read the comments to know why it would fail for a large number of digits.
Since you mentioned without using any library functions, you could do something like this.
float number;
int decimal = 0;
int decimal_found =10;
while(input[i]!='\0')
{
if((input[i] <='0' || input[i] >='9')&&input[i]!='.' )
break;
if(input[i] == '.')
decimal = 1;
if(decimal == 1)
{
number = number + (input[i] - '0')/decimal_found;
decimal_found = decimal_found*10;
}
else
{
number = number *10;
number = number + input[i] - '0';
}
i++;
}
Simply check a decimal variable to know when decimal has been reached, then use and if else to have separate conditions for the number variable
i'm newbie in C programming .
i have written this code for adding two numbers with 100 digits , but i don't know why the code does not work correctly , it suppose to move the carry but it doesn't .
and the other problem is its just ignoring the first digit (most significant digit) .
can anybody help me please ?
#include <stdio.h>
#include <ctype.h>
int sum[101] = {0};
int add(int a, int b);
void main()
{
static int a[100];
static int b[100];
char ch;
int i = 0;
int t;
for (t = 0; t != 100; ++t)
{
a[t] = 0;
}
for (t = 0; t != 100; ++t)
{
b[t] = 0;
}
do
{
ch = fgetc(stdin);
if ( isdigit(ch) )
{
a[i] = ch - 48;
++i;
}
else
break;
}
while (ch != '\n' || i == 100 || i != '\0');
i = 0;
do
{
ch = fgetc(stdin);
if ( isdigit(ch) )
{
b[i] = ch - 48;
++i;
}
else
break;
}
while (ch != '\n' || i == 100 || i != '\0');
for (;i!=0; --i)
{
add(a[i], b[i]);
}
for (i==0;i != 101; ++i)
{
printf("%d", sum[i]);
}
}
int add( int a , int b)
{
static int carry = 0;
float s = 0;
static int p = 101;
if (0 <= a+b+carry <= 9)
{
sum[p] = (a + b + carry);
carry = 0;
--p;
return 0;
}
else
{
if (10 <= a+b+carry < 20)
{
s = (((a+b+carry)/10.0 ) - 1) * 10 ;
carry = ((a+b+carry)/10.0) - (s/10);
}
else
{
s = (((a+b+carry)/10 ) - 2) * 10;
carry = ((a+b+carry)/10.0) - (s/10);
}
sum[p] = s;
--p;
return 0;
}
}
Your input loops have serious problem. Also you use i to count the length of both a and b, but you don't store the length of a. So if they type two numbers that are not equal length then you will get strange results.
The losing of the first digit is because of the loop:
for (;i!=0; --i)
This will execute for values i, i-1, i-2, ..., 1. It never executes with i == 0. The order of operations at the end of each iteration of a for loop is:
apply the third condition --i
test the second condition i != 0
if test succeeded, enter loop body
Here is some fixed up code:
int a_len;
for (a_len = 0; a_len != 100; ++a_len)
{
int ch = fgetc(stdin); // IMPORTANT: int, not char
if ( ch == '\n' || ch == EOF )
break;
a[a_len] = ch;
}
Similarly for b. In fact it would be a smart idea to make this code be a function, instead of copy-pasting it and changing a to b.
Once the input is complete, then you could write:
if ( a_len != b_len )
{
fprintf(stderr, "My program doesn't support numbers of different length yet\n");
exit(EXIT_FAILURE);
}
for (int i = a_len - 1; i >= 0; --i)
{
add(a[i], b[i]);
}
Moving onto the add function there are more serious problems here:
It's not even possible to hit the case of sum being 20
Do not use floating point, it introduces inaccuracies. Instead, doing s = a+b+carry - 10; carry = 1; achieves what you want.
You write out of bounds of sum: an array of size [101] has valid indices 0 through 100. But p starts at 101.
NB. The way that large-number code normally tackles the problems of different size input, and some other problems, is to have a[0] be the least-significant digit; then you can just expand into the unused places as far as you need to go when you are adding or multiplying.