Subtracting Hexadecimals - c

When I declare a variable as float and subtract two hexadecimal numbers, I keep getting different answer everytime I compile and and run it. Where as the if I declare an integer variable the result stays the same everytime I compile and run the code. I don't understand why storing the result in float changes everytime I compile with the difference of the same two numbers (0xFF0000 - 0xFF7FF)
int main()
{
float BlocksLeft = 0xFF0000 - 0xFF7FF;
int BLeft = 0xFF0000 - 0xFF7FF;
printf("%08x\n", BlocksLeft);
printf("%08x\n", BLeft);
}

The following line is incorrect:
printf("%08x\n", BlocksLeft);
%x format will indicate compiler the argument you give is an int. This lead to undefined behavior. I tried to compile your code and I got:
>gcc -Wall -Wextra -Werror -std=gnu99 -o stackoverflow.exe stackoverflow.c
stackoverflow.c: In function 'main':
stackoverflow.c:15:4: error: format '%x' expects argument of type 'unsigned int', but argument 2 has type 'double' [-Werror=format=]
printf("%08x\n", BlocksLeft);
^
Please, try to compile with stronger warning level, at least -Wall.
You can correct your program this way, for instance:
#include <stdio.h>
int main()
{
float BlocksLeft = 0xFF0000 - 0xFF7FF;
int BLeft = 0xFF0000 - 0xFF7FF;
printf("%08x\n", (int) BlocksLeft); // Works because BlocksLeft's value is non negative
// or
printf("%08x\n", (unsigned int) BlocksLeft);
// or
printf("%.8e\n", BlocksLeft);
printf("%08x\n", BLeft);
}

Related

how to evaluate pi in c using while loop

I'm trying to write a code in c to approximate the value of pi using a while loop. I know it is much easier to do so with a for loop but I'm trying to do so using while.
the formula I'm using to do so is in link below:
https://www.paulbui.net/wl/Taylor_Series_Pi_and_e
and the code I wrote looks like this:
#include <stdio.h>
#include <math.h>
int main(){
long n=10;
while(n>0){
double a=0;
a+=((pow(-1,n))/((2*n)+1));
n=n-1;
printf("%ld",4*a);
}
return 0;
}
the reason I used long and double type is that I wanted to do the approximation to a good preciseness but first I should do st for this problem.
thanks in advance.
You have to move a initialization before loop and make stop condition - for example, evaluating current summand. Also it is worth to calculate sign incrementally without using pow:
double a=0;
double eps= 1.0e-6; //note this series has rather slow convergence
n = 0;
double tx = 1.0;
double t = 1.0;
while(abs(tx)>eps){
tx = t / (2*n+1));
a+= tx;
printf("%f",4*a);
n++;
t = - t;
}
The posted code does not cleanly compile!
gcc -ggdb3 -Wall -Wextra -Wconversion -pedantic -std=gnu11 -c "untitled.c" -o "untitled.o"
untitled.c: In function ‘main’:
untitled.c:7:19: warning: conversion from ‘long int’ to ‘double’ may change value [-Wconversion]
7 | a+=((pow(-1,n))/((2*n)+1));
| ^
untitled.c:7:22: warning: conversion from ‘long int’ to ‘double’ may change value [-Wconversion]
7 | a+=((pow(-1,n))/((2*n)+1));
| ^
untitled.c:9:17: warning: format ‘%ld’ expects argument of type ‘long int’, but argument 2 has type ‘double’ [-Wformat=]
9 | printf("%ld",4*a);
| ~~^ ~~~
| | |
| | double
| long int
| %f
Compilation finished successfully.
Note: when there are warnings, fix those warnings. Also, when there are warnings, the compiler outputs it's best guess which is not necessarily what you wanted.

Is IEEE-754 representation used in C?

I have to encode the electron charge, which is -1.602*10-19 C, using IEEE-754. I did it manually and verified my result using this site. So I know my representation is good. My problem is that, if I try to build a C program showing my number in scientific notation, I get the wrong number.
Here is my code:
#include <stdio.h>
int main(int argc, char const *argv[])
{
float q = 0xa03d217b;
printf("q = %e", q);
return 0;
}
Here is the result:
$ ./test.exe
q = 2.688361e+09
My question: Is there another representation that my CPU might be using internally for floating point other than IEEE-754?
The line float q = 0xa03d217b; converts the integer (hex) literal into a float value representing that number (or an approximation thereof); thus, the value assigned to your q will be the (decimal) value 2,688,360,827 (which is what 0xa03d217b equates to), as you have noted.
If you must initialize a float variable with its internal IEEE-754 (HEX) representation, then your best option is to use type punning via the members of a union (legal in C but not in C++):
#include <stdio.h>
typedef union {
float f;
unsigned int h;
} hexfloat;
int main()
{
hexfloat hf;
hf.h = 0xa03d217b;
float q = hf.f;
printf("%lg\n", q);
return 0;
}
There are also some 'quick tricks' using pointer casting, like:
unsigned iee = 0xa03d217b;
float q = *(float*)(&iee);
But, be aware, there are numerous issues with such approaches, like potential endianness conflicts and the fact that you're breaking strict aliasing requirements.
Hence, q doesn't not contains the value you expect. The hex value is converted to a float with the same value (with approximation), not with the same bit-representation.
When compiled with g++ and the option -Wall, there is a warning:
warning: implicit conversion from 'unsigned int' to 'float' changes value from 2688360827 to 2688360704 [-Wimplicit-const-int-float-conversion]
Can be tested on Compiler Explorer.
This warning is apparently not supported by gcc. Instead, you can use the option -Wfloat-conversion (with is not part of -Wall -Wextra):
warning: conversion from 'unsigned int' to 'float' changes value from '2688360827' to '2.6883607e+9f' [-Wfloat-conversion]
Again on Compiler Explorer.
My problem is that if I try to build a c program showing my the number in scientific notation.
What if your target machine might or might not use IEEE754 encoding? Copying the bit pattern may fail.
If starting with a binary32 constant 0xa03d217b, code could examine it and then build up the best float available for that implementation.
#include <math.h>
#define BINARY32_MASK_SIGN 0x80000000
#define BINARY32_MASK_EXPO 0x7FE00000
#define BINARY32_MASK_SNCD 0x007FFFFF
#define BINARY32_IMPLIED_BIT 0x800000
#define BINARY32_SHIFT_EXPO 23
float binary32_to_float(uint32_t x) {
// Break up into 3 parts
bool sign = x & BINARY32_MASK_SIGN;
int biased_expo = (x & BINARY32_MASK_EXPO) >> BINARY32_SHIFT_EXPO;
int32_t significand = x & BINARY32_MASK_SNCD;
float y;
if (biased_expo == 0xFF) {
y = significand ? NAN : INFINITY; // For simplicity, NaN payload not copied
} else {
int expo;
if (biased_expo > 0) {
significand |= BINARY32_IMPLIED_BIT;
expo = biased_expo - 127;
} else {
expo = 126;
}
y = ldexpf((float)significand, expo - BINARY32_SHIFT_EXPO);
}
if (sign) {
y = -y;
}
return y;
}
Sample usage and output
#include <float.h>
#include <stdio.h>
int main() {
float e = -1.602e-19;
printf("%.*e\n", FLT_DECIMAL_DIG, e);
uint32_t e_as_binary32 = 0xa03d217b;
printf("%.*e\n", FLT_DECIMAL_DIG, binary32_to_float(e_as_binary32));
}
-1.602000046e-19
-1.602000046e-19
Note that C supports hexadecimal-floating point numbers as literals. See https://en.cppreference.com/w/cpp/language/floating_literal for details. This notation is useful to write the number in a portable way, without any concern for rounding issues as would be the case if you write it in regular decimal/scientific notation. Here's the number you're interested in:
#include <stdio.h>
int main(void) {
float f = -0x1.7a42f6p-63;
printf("%e\n", f);
return 0;
};
When I run this program, I get:
$ make a
cc a.c -o a
$ ./a
-1.602000e-19
So long as your compiler supports this notation, you need not worry about how the underlying machine represents floats, so long as this particular number fits into its float representation.

what should i change in my function so it calculates real numbers?

i am trying to write a function that repeatedly adds 0.001 to 't' and then plugs it into 'y' until 't' reaches 0.3 however the numbers come out wrong, but i've noticed that if i change float to int and change the numbers to integer, the fuction works.. what should i change so the function works properly
#include <stdio.h>
#include <math.h>
void main(void)
{
float t,y,dt;
dt = 0.001;
y = 1;
t = 0;
while (t <= 0.3)
{
y = y + dt*(sin(y)+(t)*(t)*(t));
t = t + dt;
}
printf("y is %d when t is 0.3\n" , y);
return 0;
}
i've noticed that if i change float to int and change the numbers to integer, the fuction works.. what should i change so the function works properly
as said in a remark the problem is the way you (try to) print the value in
printf("y is %d when t is 0.3\n" , y);
%d suppose the corresponding argument is an int and prints it as an int, but y is a float. Note that there is no conversion from float to int in that case because the arguments are managed through a varargs
just do
printf("y is %f when t is 0.3\n" , y);
Also change
void main(void)
to
int main()
After the changes, compilation and execution :
/tmp % gcc -pedantic -Wall -Wextra f.c -lm
/tmp % ./a.out
y is 1.273792 when t is 0.3
Note that all the calculations are done in double, so better to replace float to double to type your vars
(edit) Compiling your initial code with gcc and the option -Wall signals your problems :
/tmp % gcc -Wall f.c -lm
f.c:4: warning: return type of 'main' is not 'int'
f.c: In function 'main':
f.c:18: warning: format '%d' expects type 'int', but argument 2 has type 'double'
f.c:19: warning: 'return' with a value, in function returning void
To use both -Wall and -Wextra is the better option

uint16_t subtraction GCC compilation error

I have the following program
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
int main(void) {
uint16_t o = 100;
uint32_t i1 = 30;
uint32_t i2 = 20;
o = (uint16_t) (o - (i1 - i2)); /*Case A*/
o -= (uint16_t) (i1 - i2); /*Case B*/
(void)o;
return 0;
}
Case A compiles with no errors.
Case B causes the following error
[error: conversion to ‘uint16_t’ from ‘int’ may alter its value [-Werror=conversion]]
The warning options I'm using are:
-Werror -Werror=strict-prototypes -pedantic-errors -Wconversion -pedantic -Wall -Wextra -Wno-unused-function
I'm using GCC 4.9.2 on Ubuntu 15.04 64-bits.
Why do I get this error in Case B but not in Case A?
PS:
I ran the same example with clang compiler and both cases are compiled fine.
Integer Promotion is a strange thing. Basically, all integer values, of any smaller size, are promoted to int so they can be operated on efficiently, and then converted back to the smaller size when stored. This is mandated by the C standard.
So, Case A really looks like this:
o = (uint16_t) ((int)o - ((uint32_t)i1 - (uint32_t)i2));
(Note that uint32_t does not fit in int, so needs no promotion.)
And, Case B really looks like this:
o = (int)o - (int)(uint16_t) ((uint32_t)i1 - (uint32_t)i2);
The main difference is that Case A has an explicit cast, whereas Case B has an implicit conversion.
From the GCC manual:
-Wconversion
Warn for implicit conversions that may alter a value. ....
So, only Case B gets a warning.
Your case B is equivalent to:
o = o - (uint16_t) (i1 - i2); /*Case B*/
The result is an int which may not fit in uint16_t, so, per your extreme warning options, it produces a warning (and thus an error since you're treating warnings as errors).

"comparison between signed and unsigned integer expressions" with only unsigned integers

This warning should not appear for this code should it?
#include <stdio.h>
int main(void) {
unsigned char x = 5;
unsigned char y = 4;
unsigned int z = 3;
puts((z >= x - y) ? "A" : "B");
return 0;
}
z is a different size but it is the same signedness. Is there something about integer conversions that I'm not aware about? Here's the gcc output:
$ gcc -o test test.c -Wsign-compare
test.c: In function ‘main’:
test.c:10:10: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
puts((z >= x - y) ? "A" : "B");
^
$ gcc --version
gcc (Debian 4.9.1-15) 4.9.1
If z is an unsigned char I do not get the error.
The issue is that additive operators perform the usual arithmetic conversions on arithmetic types which. In this case it results in the integer promotions being performed on the operands, which results in unsigned char being converted to int since signed int can represent all the values of the type of unsigned char.
A related thread Why must a short be converted to an int before arithmetic operations in C and C++? explains the rationale for promotions.
C has this concept called "Integer Promotion".
Basically it means that all maths is done in signed int unless you really insist otherwise, or it doesn't fit.
If I put in the implicit conversions, your example actually reads like this:
puts((z >= (int)x - (int)y) ? "A" : "B");
So, now you see the signed/unsigned mismatch.
Unfortunately, you can't safely correct this problem using casts alone. There are a few options:
puts((z >= (unsigned int)(x - y)) ? "A" : "B");
or
puts((z >= (unsigned int)x - (unsigned int)y) ? "A" : "B");
or
puts(((int)z >= x - y) ? "A" : "B");
But they all suffer from the same problem: what if y is larger than x, and what if z is larger than INTMAX (not that it will in the example)?
A properly correct solution might look like this:
puts((y > x || z >= (unsigned)(x - y)) ? "A" : "B")
In the end, unless you really need the extra bit, it usually best to avoid unsigned integers.

Resources