I know the solution is ugly and technically incorrect but I don't understand why the code doesn't work.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main (int argc, char *argv[]) {
int u;
scanf("%d", &u);
printf("absValue = %u\n", u);
return 0;
}
%u specifies an unsigned decimal character but when I input a negative value, it gives
absValue = 4294967293
Alternatively, with the if command, how to convert the negative sign to positive?
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main (int argc, char *argv[]) {
int n;
scanf("%d", &n);
if(n < 0) {
printf("absValue = -%d\n", n);
} else {
printf("absValue = %d\n", n);
}
return 0;
}
The shortest solution in your first piece of code is to change the printf statement as follows:
printf("absValue = %u\n", (unsigned)((u<0)?-u:u));
This will print the absolute value of u. The type conversion (unsigned) ensures that the data type is as expected by printf. The statement (u<0)?-u:u uses the conditional operator to select the value -u if the condition (u<0) is true and u if the condition is false (i.e. u>=0).
The problem in your code is that u is a signed integer which means its value is stored using the Two's complement representation in 4 bytes(*) and printf is not intelligent. When you tell printf to display an unsigned integer, then printf will take the 4 bytes holding u and interpret them as an unsigned integer. Since negative numbers in Two's complement are stored as large positive integers, that is the result you see.
(*) The use of Two's complement and the int size of 4 is machine-dependent, but common.
As an alternative, you can also use the standard C function abs() (or one of its related functions):
7.22.6.1 The abs, labs and llabs functions
Synopsis
#include <stdlib.h>
int abs(int j);
long int labs(long int j);
long long int llabs(long long int j);
Description
The abs, labs, and llabs functions compute the absolute value of
an integer j. If the result cannot be represented, the behavior is
undefined.
Returns
The abs, labs, and llabs, functions return the absolute value.
Footnotes
The absolute value of the most negative number cannot be represented
in two's complement.
Note the footnote "The absolute value of the most negative number cannot be represented in two's complement." and "If the result cannot be represented, the behavior is undefined." Strictly speaking, you'd likely need to use long long int and llabs() to avoid undefined behavior in converting INT_MIN to a positive value, assuming a 32-bit int value, and long is often 32-bits, even on 64-bit Windows.
However, since double values are likely implemented in IEEE format with 53 bits of precision, a 32-bit int value can be converted to double with no loss of precision, so you can use the fabs() function to get the absolute value of a 32-bit int value in one call:
7.12.7.2 The fabs functions
Synopsis
#include <math.h>
double fabs(double x);
float fabsf(float x);
long double fabsl(long double x);
The fabs functions compute the absolute value of a floating-point
number x.
So your code would be:
#include <stdio.h>
#include <math.h>
int main (int argc, char *argv[]) {
int u;
scanf("%d", &u);
printf("absValue = %u\n", (unsigned) fabs((double) u));
return 0;
}
Note that in (unsigned) fabs((double) u), casting u to double is not strictly necessary, as the int value will be implicitly converted to a double because of the double fabs(double) function prototype from stdlib.h. But the cast back to unsigned is exremely necessary to pass the unsigned int value you want to pass to printf().
You could also do this:
#include <stdio.h>
#include <math.h>
int main (int argc, char *argv[]) {
int u;
scanf("%d", &u);
unsigned int absValue = fabs(u);
printf("absValue = %u\n", absValue);
return 0;
}
That works because unsigned int absValue is explicitly an unsigned int.
Also, on modern CPUs, conversion between int and double is usually done by a single relatively fast instruction.
How to write absolute value in c?
The shortest solution :
#include <stdlib.h>
printf("absValue = %d\n", abs(u)); // clear and concise - yet see below
Both printf("%d\n", abs(u)); and printf("%u\n", (unsigned)((u<0)?-u:u)); suffer the same problem: undefined behavior (UB) when n == INT_MIN1. The signed negation of INT_MIN is the UB.
At least abs(u) is clear, unlike (unsigned)((u<0)?-u:u).
To print the absolute value of an int, code could negate negative values with:
(-1 - n) + 1u or
-(unsigned)n or
0u - n
... and end up with an unsigned.2
I'd go for the simplest when a full range |int| is sought.
printf("absValue = %u\n", n < 0 ? 0u - n : (unsigned) n);
Using long, long long or double poses their own troubles and portability. None warranted here.
1 when int is 2's complement encoded - very common.
2 C specified UINT_MAX >= INT_MAX. In the very rare implementations today, INT_MAX == INT_MAX is possible and code needs to resort to a wider type when int is non 2's complement.
printf doesn't convert the strings, but rather expects them converted. I would generally prefer to use the standard abs function which is declared in stdlib.h. This uses strtol to convert an argument to a long then convert that to an int. Nota bene, that, for example, if your machine uses two's-complements, calling abs(INT_MIN) produces undefined behaviour and should be dealt with. (Edited: error detection now complies with non-POSIX systems; see comments.)
#include <stdio.h> /* perror, printf */
#include <stdlib.h> /* strtol, abs */
#include <limits.h> /* INT_MIN, INT_MAX */
#include <errno.h> /* errno, ERANGE */
int main(int argc, char *argv[]) {
int u;
long input;
char *end;
/* Require one argument. */
if(argc != 2) return printf("Usage <number>\n"), EXIT_SUCCESS;
/* `input` is converted from `argv[1]`, if it's 0, check that it actually
read 0; check to see garbage characters at the end; check to see if the
`input` is a) less then `INT_MIN`; b) also if `-INT_MAX < 0`, check that
it is not lower than this value, because that will lead to undefined
`abs`; c) more then `INT_MAX` -> if so, set `ERRNO` and enter the if. */
if( ((input = strtol(argv[1], &end, 0)) == 0 && end == argv[1])
|| (*end != '\0' && (errno = EILSEQ, 1))
|| ((input < INT_MIN || (-INT_MAX < 0 && input < -INT_MAX)
|| input > INT_MAX) && (errno = ERANGE, 1)) )
return perror("Input"), EXIT_FAILURE;
/* We are pretty sure this cast is safe, now: `int abs(int)`. */
u = abs((int)input);
printf("absValue(%ld) = %d\n", input, u);
return EXIT_SUCCESS;
}
Checking edge cases,
bin/abs 2147483647
absValue(2147483647) = 2147483647
bin/abs 2147483648
Input: Result too large
bin/abs -2147483648
Input: Result too large
bin/abs -2147483647
absValue(-2147483647) = 2147483647
bin/abs
Usage <number>
bin/abs 0x10
absValue(16) = 16
bin/abs asdf
Input: Invalid argument
bin/abs 1a
Input: Illegal byte sequence
this is a function to get the absolute value of a number without using abs() function.
int abs_value(int *a){
return *a < 0 ? -*a: *a;
}
If you want to get the absolute difference between two numbers, here's how:
int abs_diff (int *a, int*b) {
return *a > *b ? *a - *b : *b - *a;
}
Related
I want to write code that, if I input a decimal number like 612.216, I can print it as a 612216 (actually convert it to integer). However, the program changes my number to something like 2162160000000000000000001 and I don't what to do about it.
This is my code:
#include <stdio.h>
#include <math.h>
int main() {
long double x;
scanf_s("%Lf", &x);
while (floor(x)!=x)
x = x * 10;
printf("%Lf", x);
return 0;}
How about this:
#include <stdio.h>
int main() {
double number = 612.216;
char number_as_string[20];
snprintf(number_as_string,"%lf", number);
for(int i = 0; number_as_string[i] != '\0'; i++)
if(number_as_string[i] != '.')
printf("%c", number_as_string[i]);
return 0;
}
The downside is the statically allocated array. You can use snprintf to convert the double into an array of chars.
The floating point representation isn't exact so there is a very very small error in any floating point number. You could try something like this pseudocode,
while ((x - floor(x) > 0.0000000000000000001)
x *= 10;
Your math library might define a better number to use like FLT_MIN or some such ;)
The problem with your floor(x)!=x check is that it doesn't take into account any inaccuracy in the representation of the input long double number. (In the example given, this causes an 'extra' 0.0000000000000000000001 to be added to the actual value.) See Is floating point math broken? for more information on such inaccuracies inherent in any representation of floating-point numbers.
To fix this in your code, you can compare the difference between floor(x) and x to a given 'tolerance' - if it's less than that, consider the loop finished. You can use a value derived from the LDBL_EPSILON constant as a typical value for that 'tolerance', though you may like to experiment with different values.
Here is a possible code solution:
#include <stdio.h>
#include <math.h>
#include <float.h> // For the LDBL_EPSILON definition
int main()
{
long double x;
scanf_s("%Lf", &x);
while ((x - floor(x)) > (LDBL_EPSILON * x * 10)) // Try changing the "10" value!
x = x * 10;
printf("%.0Lf", x); // Add the ".0" to remove the trailing ".000000" in the output
return 0;
}
long double can store many finite values exactly. There are all of the form:
+/- some_integer * 2some_exponent
Since "612.216" is not represent-able like that (0.216 cannot be expressed as a binary fraction like 0.25 can), a nearby long double value was used like ~612.2160000000000000253...
Also, OP's repeated use of x = x * 10; adds small rounding errors and does not pose a reasonable conversion limit.
A alternative approach uses LDBL_DIG (the number of significant decimal digits that round trip from decimal text to long double to decimal text unchanged) and to print the double to a buffer. Let *printf() do the heavy lifting of converting a double to the best decimal text.
#include <float.h>
#include <stdio.h>
// To print up to the LDBL_DIG most significant digits w/o trailing zeros:
void print_sig_digits(long double x) {
// - d . ddd....ddd e - expo \0
char buf[1 + 1 + 1 + (LDBL_DIG-1) + 1 + 1 + 8 +1];
#define e_OFFSET (1 + 1 + 1 + (LDBL_DIG-1))
// Print using exponential format
snprintf(buf, sizeof buf, "%+.*Le", LDBL_DIG, x);
buf[e_OFFSET] = '\0'; // End string at 'e'
for (int i = e_OFFSET - 1; buf[i] == '0'; i--) {
buf[i] = '\0'; // Lop off trailing '0'
}
buf[2] = buf[1]; // Copy first digit over '.'
printf("%s\n", &buf[2]);
}
int main(void) {
printf("LDBL_DIG: %d\n", LDBL_DIG);
print_sig_digits( 612.216L);
print_sig_digits( 1.0L/7);
print_sig_digits( 0.000123L);
return 0;
}
Output
LDBL_DIG: 18
612216
142857142857142857
123
Here is the snippets of my code and the output. Suggest the reason behind a negative result when large positive numbers are multiplied?
int printM(int v)
{
int g=v+5;
g=g*3344564*452346;
printf("The value of g is %d\n",g);
return g;
}
int main()
{
int f=0;
int a=45;
a=a+334;
a=a+534534;
a=a+939;
a=a+45345654645;
f=printM(a);
return 0;
}
output:
pravesh#pravesh-Aspire-4552:~/Desktop/c_d$ gcc -g linked_list.c
pravesh#pravesh-Aspire-4552:~/Desktop/c_d$ ./a.out
The value of g is -377042000
`
What you end up with when overflowing an int is undefined behaviour. INT_MAX is defined to be the largest value that an int can represent on your platform.
Note that overflowing an unsigned is well defined: it wraps around modulo UINT_MAX + 1.
(For what it's worth, what's probably happening in your case is that the int is wrapping around in exactly the same way as it would do if the memory is interpreted as an unsigned).
I am writing a program in C to calculate the range of different data types. Please look at the following code:
#include <stdio.h>
main()
{
int a;
long b;
for (a = 0; a <= 0; --a)
;
++a;
printf("INT_MIN: %d\n", a);
for (a = 0; a >= 0; ++a)
;
--a;
printf("INT_MAX: %d\n", a);
for (b = 0; b <= 0; --b)
;
++b;
printf("LONG_MIN: %d\n", b);
for (b = 0; b >= 0; ++b)
;
--b;
printf("LONG_MAX: %d\n", b);
}
The output was:
INT_MIN: -32768
INT_MIN: 32767
LONG_MIN: 0
LONT_MAX: -1
The program took a long pause to print the long values. I also put a printf inside the third loop to test the program (not mentioned here). I found that b did not exit the loop even when it became positive.
I used the same method of calculation. Why did it work for int but not for long?
You are using the wrong format specifier. Since b is of type long, use
printf("LONG_MIN: %ld\n", b);
In fact, if you enabled all warnings, the compiler probably would warn you, e.g:
t.c:19:30: warning: format specifies type 'int' but the argument has type 'long' [-Wformat]
printf("LONG_MIN: %d\n", b);
In C it is undefined behaviour to decrement a signed integer beyond its minimum value (and similiarly for incrementing above the maximum value). Your program could do literally anything.
For example, gcc compiles your program to an infinite loop with no output.
The proper approach is:
#include <limits.h>
#include <stdio.h>
int main()
{
printf("INT_MIN = %d\n", INT_MIN);
// etc.
}
In
printf("LONG_MIN: %d\n", b);
the format specifier is %d which works for integers(int). It should be changed to %ld to print long integers(long) and so is the case with
printf("LONG_MAX: %d\n", b);
These statements should be
printf("LONG_MIN: %ld\n", b);
&
printf("LONG_MAX: %ld\n", b);
This approach may not work for all compilers(eg gcc) and an easier approach would be to use limits.h.
Also check Integer Limits.
As already stated, the code you provided invokes undefined behavior. Thus it could calculate what you want or launch nuclear missiles ...
The reason for the undefined behavior is the signed integer overflow that you are provoking in order to "test" the range of the data types.
If you just want to know the range of int, long and friends, then limits.h is the place to look for. But if you really want ...
[..] to calculate the range [..]
... for what ever reason, then you could do so with the unsigned variant of the respective type (though see the note at the end), and calculate the maximum like so:
unsigned long calculate_max_ulong(void) {
unsigned long follow = 0;
unsigned long lead = 1;
while (lead != 0) {
++lead;
++follow;
}
return follow;
}
This only results in an unsigned integer wrap (from the max value to 0), which is not classified as undefined behavior. With the result from above, you can get the minimum and maximum of the corresponding signed type like so:
assert(sizeof(long) == sizeof(unsigned long));
unsigned long umax_h = calculate_max_ulong() / 2u;
long max = umax_h;
long min = - max - 1;
(Ideone link)
Assuming two's complement for signed and that the unsigned type has only one value bit more than the signed type. See ยง6.2.6.2/2 (N1570, for example) for further information.
you could say that I am relatively new to C, but I need clarification on a question.
I have a char[] that represents a number. If this char[] is longer than LONG_MAX I want to tell the user it is too long. The problem is that when I compare its value to a float, it becomes truncated. Here's what I mean.
int main(int argc, char ** argv) {
char str[] = argv[1]; /* I set it to 9223372036854775809, only +1 higher than LONG_MAX */
double l = atof(str);
double j = LONG_MAX;
printf("%lf\n", l); /* This prints 9223372036854775808.000000, which is LONG_MAX ??? WHY?? */
printf("%lf\n", j); /* This prints same as above, 9223372036854775808.000000 */
printf("%s\n", l > j ? "true" : "false"); /* false */
return 0; /* what am I doing wrong? */
}
UPDATE:
I tried your iret solution and I still run into the same rounding problem
j = LONG_MAX;
int iret = sscanf (str, "%lf", &l);
if (iret != 1)
return 0; /* conversion was bad */
else {
if (l > j || l < -(j))
return 0; /* too small or too large */
}
printf("%lf\n", l);
printf("%lf\n", j);
printf("%s\n", l > j ? "true" : "false");
You can check for overflow easily enough with strtol, but it requires a little extra work.
const char *str = ...;
char *e;
long x;
errno = 0;
x = strtol(str, &e, 0);
if (!*str || *e) {
fprintf(stderr, "invalid number: %s\n", str);
exit(1);
}
if ((x == LONG_MAX || x == LONG_MIN) && errno == ERANGE) {
fprintf(stderr, "number too large: %s\n", str);
exit(1);
}
Now, let's talk about the problem with strtod (or atof, which is just a broken version of strtod).
If you convert 9223372036854775809 to a double, then 9223372036854775808 is correct. A double has 53 bits of precision, and a 64-bit long has, well, 64 bits. As soon as you start working with floating-point numbers you need to be prepared for rounding.
For example, there is round-off error in the following code. Can you spot it?
double x = 0.1;
Footnote: I'm assuming 64-bit long and IEEE double-precision double here.
Per the "man" page for atof:
http://linux.die.net/man/3/atof
The atof() function converts the initial portion of the string pointed
to by nptr to double. ... atof() does not detect errors.
Which is why I prefer to use "sscanf" instead:
int iret = sscanf (SOME_TEXT, "%lf", &SOME_DOUBLE);
If "iret != 1", then I know an error occurred, and can take the appropriate action.
IMHO...
PS:
Why aren't you declaring "l" and "j". Naughty naughty! You should always declare your variables, even in FORTRAN and Basic ;)
And why not declare them as float ("%f") or double ("%lf")?
I believe the reason why you are getting the value "9223372036854775808.000000" for both your inputs is due to the precision limitations of floating point approximations.
By the way, the value isn't LONG_MAX, but LONG_MAX + 1 -> 2^63.
By definition, the representation of LONG_MAX exactly (as an integer) requires 63 bits of precision. However, in a 64-bit floating point representation like double, there are only 53 bits of precision, since the other bits are required to store the sign and exponent. That's why both LONG_MAX and LONG_MAX + 2 end up being rounded to 9223372036854775808 <=> 2^63.
To handle this case properly, perhaps look at strtol which will set an error code when the input is out of range.
Your long seems to be 63 bits. A float has 23 significant bits (or 24 with leading 1). Your longs are the exactly the same in the upper 24 bits. So they become the same.
A float is basically mantissa*2^exponent. The exponent makes sure that the magnitude still matches. But you only have 23 bits of mantissa. So it becomes top23bitsoflong*2^(numberofremainingbits).
This is a bit simplified ignoring leading one and exponent bias.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
signed to unsigned conversions
A riddle (in C)
I am trying to understand why this program is not working
#include<stdio.h>
#define TOTAL_ELEMENTS (sizeof(array) / sizeof(array[0]))
int array[] = {23,34,12,17,204,99,16};
int main()
{
int d;
for(d=-1;d <= (TOTAL_ELEMENTS-2);d++)
printf("%d\n",array[d+1]);
return 0;
}
I came across this program when I was going through automatic type conversions in C.But I don't understand how conversions happen between signed and unsigned data types.Please explain.
Thank you,
Harish
sizeof() is of type unsigned, wile d is signed.
you check if d is smaller then an unsigned integer. Thus, the signed d is converted to unsinged.
But the bits representaion of the signed -1 when read as unsigned is greater then 2^31, and obviously greater then TOTAL_ELEMENTS-2, thus the condition is never met and you do not enter the for loop even once.
Look at this code snap, it might clear up things for you:
#include <stdio.h>
#include <stdlib.h>
int main() {
unsigned int x = 50;
int y = -1;
printf("x < y is actually %u < %u which yields %u\n", y,x,y < x);
return 0;
}
The above code prints:
x < y is actually 4294967295 < 50 which yields 0