C output of hexadecimal division different from all other sources - c

I want to divide two hex numbers:
for example: 88555680/10000
Now, from online hex calculators, I find:
8855 as result here
8855.568 as result here
And in python I find:
>>> hex(int("0x88555680",16)//int("0x10000", 16))
'0x8855'
Here is my C code:
# include <stdio.h>
int main() {
int a = 0x88555680;
int b = 0x10000;
int c = a/b;
printf("a%x, b%x, c%x\n", a, b, c);
}
With output:
a88555680, b10000, cffff8856
In C, I find 8856, while with Python, and online calculators, I find 8855
Question: Why is the C output not 8855? Why is it 8856? Should it not be 8855.something and then truncated towards 0, thus 8855?
I'm very new to C, it might be an obvious error.

On common systems int is a 32-bit type whose max value is 0x7FFFFFFF. Your value of 0x88555680 is out of range for int. The compiler should warn you about this; if you don't see a warning then I recommend adjusting compiler settings.
Also your code causes undefined behaviour by using %x to print an int. The %x specifier may only be used for unsigned int.
To fix your code in this case use unsigned int instead of int for all 3 variables. If you want to deal with larger numbers you can use unsigned long long, or uint64_t. (In those cases you will need to update the printf format specifiers too).

Related

How to convert 64 bit hex value to double in c?

I'm using a gps module through which I'm getting the string
"0x3f947ae147ae147b"
which I need to convert to double. The expected value is 0.02.
I referred the following website for the reference
https://gregstoll.com/~gregstoll/floattohex/
How I can convert value in the C?
3F947AE147AE147B16 is the encoding for an IEEE-754 binary64 (a.k.a. “double precision”) datum with value 0.0200000000000000004163336342344337026588618755340576171875. Supposing your C implementation uses that format for double and has 64-bit integers with the same endianness, you can decode it (not convert it) by copying its bytes into a double and printing them:
#include <errno.h>
#include <limits.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char *string = "0x3f947ae147ae147b";
// Set errno to zero before using strtoull.
errno = 0;
char *end;
unsigned long long t = strtoull(string, &end, 16);
// Test whether stroull did not accept all characters.
if (*end)
{
fprintf(stderr,
"Error, string \"%s\", is not a proper hexadecimal numeral.\n",
string);
exit(EXIT_FAILURE);
}
// Move the value to a 64-bit unsigned integer.
uint64_t encoding = t;
/* Test whether the number is too large, either because strtoull reported
an error or because it does not fit in a uint64_t.
*/
if ((t == ULLONG_MAX && errno) || t != encoding)
{
fprintf(stderr, "Error, string \"%s\", is bigger than expected.\n",
string);
exit(EXIT_FAILURE);
}
// Copy the bytes into a double.
double x;
memcpy(&x, &encoding, sizeof x);
printf("%.9999g\n", x);
}
This should output “0.0200000000000000004163336342344337026588618755340576171875”.
If your C implementation does not support this format, you can decode it:
Separate the 64 bits into s, e, f, where s is the leading bit, e is the next 11 bits, and f is the remaining 52 bits.
If e is 2047 and f is zero, report the value is +∞ or −∞, according to whether s is 0 or 1, and stop.
If e is 2047 and f is not zero, report the value is a NaN (Not a Number) and stop.
If e is not zero, add 252 to f. If e is zero, change it to one.
The magnitude of the represented value is f•2−52•2e−1023, and its sign is + or − according to whether s is 0 or 1.
The usual way to convert a string of digits like "0x3f947ae147ae147b" into an actual integer is with one of the "strto" functions. Since you have 64 bits, and you're not interested in treating them as a signed integer (since you're about to, instead, try to treat them as a double), the appropriate choice is strtoull:
#include <stdlib.h>
char *str = "0x3f947ae147ae147b";
uint64_t x = strtoull(str, NULL, 16);
Now you have your integer, as you can verify by doing
printf("%llx\n", x);
But now the question is, how do you treat those bits as an IEEE-754 double value, instead of an integer? There are at least three ways to do it, in increasing levels of portability.
(1) Use pointers. Take a pointer to your integer value x, change it do a double pointer, then indirect on it, forcing the compiler to (try to) treat the bits of x as if they were a double:
double *dp = (double *)&x;
double d = *dp;
printf("%f\n", d);
This was once a decent and simple way to do it, but it is no longer legal as it runs afoul of the "strict aliasing rule". It might work for you, or it might not. Theoretically this sort of technique can also run into issues with alignment. For these reasons, this technique is not recommended.
(2) Use a union:
union u { uint64_t x; double d; } un;
un.x = strtoull(str, NULL, 16);
printf("%f\n", un.d);
Opinions differ on whether this technique is 100% strictly legal. I believe it's fine in C, but it may not be in C++. I'm not aware of machines where it won't work.
(3) Use memcpy:
#include <string.h>
uint64_t x = strtoull(str, NULL, 16);
double d;
memcpy(&d, &x, 8);
printf("%f\n", d);
This works by, literally, copying the individual bytes of the unsigned long int value x into the bytes of the double variable d. This is 100% portable (as long as x and d are the same size). I used to think it was wasteful, due to the extra function call, but these days it's a generally recommended technique, and I'm told that modern compilers are smart enough to recognize what you're trying to do, and emit perfectly efficient code (that is, just as efficient as techniques (1) or (2)).
Now, one other portability concern is that this all assumes that type double on your machine is in fact implemented using the same IEEE-754 double-precision format as your incoming hex string representation. That's actually a very safe assumption these days, although it's not strictly guaranteed by the C standards. If you like to be particularly careful about type correctness, you might add the lines
#include <assert.h>
assert(sizeof(uint64_t) == sizeof(double));
and change the memcpy call (if that's what you end up using) to
memcpy(&d, &x, sizeof(double));
(But note that these last few changes only guard against unexpected system-specific discrepancies in the size of type double, not its representation.)
One further point. Note that one technique which will most definitely not work is the superficially obvious
d = (double)x;
That line would perform an actual conversion of the value 0x3f947ae147ae147b. It won't just reinterpret the bits. If you try it, you'll get an answer like 4581421828931458048.000000. Where did that come from? Well, 0x3f947ae147ae147b in decimal is 4581421828931458171, and the closest value that type double can represent is 4581421828931458048. (Why can't type double represent the integer 4581421828931458171 exactly? Because it's a 62-bit number, and type double has at most 53 bits of precision.)

Why is there a difference between these 2 results?

I am a beginner in C programming language, I don't understand why there is -1 in the 2nd command line. thank you in advance.
printf("The maximum value of UNSIGNED INT = %u\n", UINT_MAX);
result: 4294967295
printf("The maximum value of UNSIGNED INT = %d\n", UINT_MAX);
result : -1 (why?)
%d tells printf to format an int that you pass it. You did not pass it an int; you passed it an unsigned int. It has no knowledge of that and attempts to work with the data that you passed.
“-1” is a common result because the bits for the maximum unsigned int (all bits 1) is the same as the bits used for the two’s complement −1 int (also all bits 1). However, when you mismatch format conversions and arguments, a variety of things can go wrong. C was developed as a language for telling the computer what to do in a human-friendly way (using symbol names and arithmetic operations and convenient functions rather than assembly language instructions). This makes it easy to tell the computer to do wrong things. This is unlike other languages that add a lot of rules and software to handle things for you automatically, such as managing types more strictly.

The problem about printf function to "output float with %d" in C

I am a newbie to the C language. When I was learning floating point numbers today, I found the following problems.
float TEST= 3.0f;
printf("%x\n",TEST);
printf("%d\n",TEST);
first output:
9c9e82a0
-1667333472
second output:
61ea32a0
1642738336
As shown above, each execution will output different results. I have checked a lot of IEEE 754 format and still don't understand the reasons. I would like to ask if anyone can explain or provide keywords for me to study, thank you.
-----------------------------------Edit-----------------------------------
Thank you for your replies. I know how to print IEEE 754 bit pattern. However, as Nate Eldredge, chux-Reinstate Monica said, using %x and %d in printf is undefined behavior. If there is no floating point register in our device, how does it work ? Is this described in the C99 specification?
Most of the time, when you call a function with the "wrong kind" (wrong type) of argument, an automatic conversion happens. For example, if you write
#include <stdio.h>
#include <math.h>
printf("%f\n", sqrt(144));
this works just fine. The compiler knows (from the function prototype in <math.h>) that the sqrt function expects an argument of type double. You passed it the int value 144, so the compiler automatically converted that int to double before passing it to sqrt.
But this is not true for the printf function. printf accepts arguments of many different types, and as long as each argument is right for the particular % format specifier it goes with in the format string, it's fine. So if you write
double f = 3.14;
printf("%f\n", f);
it works. But if you write
printf("%d\n", f); /* WRONG */
it doesn't work. %d expects an int, but you passed a double. In this case (because printf is special), there's no good way for the compiler to insert an automatic conversion. So, instead, it just fails to work.
And when it "fails", it really fails. You don't even necessarily get anything "reasonable", like an integer representing the bit pattern of the IEEE-754 floating-point number you thought you passed. If you want to inspect the bit pattern of a float or double, you'll have to do that another way.
If what you really wanted to do was to see the bits and bytes making up a float, here's a completely different way:
float test = 3.14;
unsigned char *p = (unsigned char *)&test;
int i;
printf("bytes in %f:", test);
for(i = 0; i < sizeof(test); i++) printf(" %02x", p[i]);
printf("\n");
There are some issues here with byte ordering ("endianness"), but this should get you started.
To print hex (ie how it is represented in the memory) representation of the float:
float TEST= 3.0f;
int y=0;
memcpy(&y, &TEST, sizeof(y));
printf("%x\n",y);
printf("%d\n",y);
or
union
{
float TEST;
int y;
}uf = {.y = 0};
uf.TEST = 3.0f;
printf("\n%x\n",(unsigned)uf.y);
printf("%d\n",uf.y);
Both examples assuming sizeof(float) <= sizeof(int) (if they are not equal I need to zero the integer)
And the result (same for both):
40400000
1077936128
As you can see it is completely different from your one.
https://godbolt.org/z/Kr61x6Kv3

Handling numbers in C

Couldnt understand how numbers are handled in C. Could anyone point to a good tutorial.
#include<stdio.h>
main()
{
printf("%f",16.0/3.0);
}
This code gave: 5.333333
But
#include<stdio.h>
main()
{
printf("%d",16.0/3.0);
}
Gave some garbage value: 1431655765
Then
#include<stdio.h>
main()
{
int num;
num=16.0/3.0;
printf("%d",num);
}
Gives: 5
Then
#include<stdio.h>
main()
{
float num;
num=16/3;
printf("%f",num);
}
Gives: 5.000000
printf is declared as
int printf(const char *format, ...);
the first arg (format) is string, and the rest can be anything. How the rest of the arguments will be used depending on the format specifiers in format. If you have:
printf("%d%c", x, y);
x will be treated as int, y will be treated as char.
So,
printf("%f",16.0/3.0);
is ok, since you ask for float double (%f), pass float double(16.0/3.0)
printf("%d",16.0/3.0);
you ask for int(%d), you pass float double (double and int have different internal representation) so, the bit representation of 16.0/3.0 (double) corresponds to bit representation of 1431655765(int).
int num;
num=16.0/3.0;
compiler knows that you are assigning to int, and converts it for you. Note that this is different than the previous case.
Ok, the first 1 is giving correct value as expected.
Second one you are passing a float while it is treating it as an int (hence the "%d" which is for displaying int datatypes, it is a little complicated to explain why and since it appears your just starting I wouldn't worry about why "%d" does this when passed a float) reading it wrong therefore giving you a wierd value. (not a garbage value though).
Third one it makes 16.0/3.0 an int while assigning it to the int datatype which will result in 5. Because while making the float an int it strips the decimals regardless of rounding.
In the fourth the right hand side (16/3) is treated as an int because you don't have the .0 zero at the end. It evaluates that then assigns 5 to float num. Thus explaining the output.
It is because the formatting strings you are choosing do not match the arguments you are passing. I suggest looking at the documentation on printf. If you have "%d" it expects an integer value, how that value is stored is irrelevant and likely machine dependent. If you have a "%f" it expects a floating point number, also likely machine dependent. If you do:
printf( "%f", <<integer>> );
the printf procedure will look for a floating point number where you have given an integer but it doesn't know its and integer it just looks for the appropriate number of bytes and assumes that you have put the correct things there.
16.0/3.0 is a float
int num = 16.0/3.0 is a float converted to an int
16/3 is an int
float num = 16/3 is an int converted to a float
You can search the web for printf documentation. One page is at http://linux.die.net/man/3/printf
You can understand numbers in C by using concept of Implecit Type Conversion.
During Evaluation of any Expression it adheres to very strict rules of type Conversion.
and your answer of expression is depends on this type conversion rules.
If the oparands are of different types ,the 'lower' type is automatically converted into the 'higher' type before the operation proceeds.
the result is of the higher type.
1:
All short and char are automatically converted to int then
2:
if one of the operands is int and the other is float, the int is converted into float because float is higher than an ** int**.
if you want more information about inplicit conversion you have to refer the book Programming in ANSI C by E Balagurusamy.
Thanks.
Bye:DeeP
printf formats a bit of memory into a human readable string. If you specify that the bit of memory should be considered a floating point number, you'll get the correct representation of a floating point number; however, if you specify that the bit of memory should be considered an integer and it is a floating point number, you'll get garbage.
printf("%d",16.0/3.0);
The result of 16.0/3.0 is 5.333333 which is represented in Single precision floating-point format as follows
0 | 10101010 | 10101010101010101010101
If you read it as 32bit integer value, the result would be 1431655765.
num=16.0/3.0;
is equivalent to num = (int)(16.0/3.0). This converts the result of float value(5.33333) to integer(5).
printf("%f",num);
is same as printf("%f",(float)num);

C convert hex to decimal format

Compiling on linux using gcc.
I would like to convert this to hex. 10 which would be a.
I have managed to do this will the code below.
unsigned int index = 10;
char index_buff[5] = {0};
sprintf(index_buff, "0x%x", index);
data_t.un32Index = port_buff;
However, the problem is that I need to assign it to a structure
and the element I need to assign to is an unsigned int type.
This works however:
data_t.un32index = 0xa;
However, my sample code doesn't work as it thinks I am trying to convert
from an string to a unsigned int.
I have tried this, but this also failed
data_t.un32index = (unsigned int) *index_buff;
Many thanks for any advice,
Huh? The decimal/hex doesn't matter if you have the value in a variable. Just do
data_t.un32index = index;
Decimal and hex are just notation when printing numbers so humans can read them.
For a C (or C++, or Java, or any of a number of languages where these types are "primitives" with semantics closely matching those of machine registers) integer variable, the value it holds can never be said to "be in hex".
The value is held in binary (in all typical modern electronic computers, which are digital and binary in nature) in the memory or register backing the variable, and you can then generate various string representations, which is when you need to pick a base to use.
I agree with the previous answers, but I thought I'd share code that actually converts a hex string to an unsigned integer just to show how it's done:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char *hex_value_string = "deadbeef";
unsigned int out;
sscanf(hex_value_string, "%x", &out);
printf("%o %o\n", out, 0xdeadbeef);
printf("%x %x\n", out, 0xdeadbeef);
return 0;
}
Gives this when executed:
emil#lanfear /home/emil/dev $ ./hex
33653337357 33653337357
deadbeef deadbeef
However, my sample code doesn't work as it thinks I am trying to convert from an string to a unsigned int.
This is because when you write the following:
data_t.un32index = index_buff;
you do have a type mismatch. You are trying to assign a character array index_buff to an unsigned int i.e. data_t.un32index.
You should be able to assign the index as suggested directly to data_t.un32index.

Resources