I'm trying to write an algorithm to convert a hexadecimal number to a floating point number and vice versa. This is part of an assignment, the program is supposed to receive either an 8 digit hexadecimal number that starts with '0x' or a floating point number, and using the computer's 'built in IEEE 754 capabilities' convert the number to hex or float. The code should be in C.
My approach is the following. Store the input by the user as a string. Pass the input char array to a method that checks if it's a hexadecimal number by checking the first two positions of the array, which should be 0 and X (assume all hex numbers are passed this way). If this is the case, then I check that the hex is in the appropriate form, i.e not too many digits or numbers outside the 0-15 range (also considering the ABCDEF convention).
So, my problem is, I don't know how to turn this array back into a number that I can use to convert to floating point. I thought about using sscanf to turn it back into a float but I don't know enough C and haven't found any good sources online
Can somebody point me in the right direction? I also thought about storing the user input both as a string and a number at the same time, but I am not sure if this is possible.
Here are the two form checking functions and the incomplete main method:
int is_hex(char arr[])
{
if (arr[0] == '0' && (arr[1] == 'x' || arr[1] == 'X')) {
return 1;
}
return 0;
}
int check_if_good(char arr[])
{
if (is_hex(arr)) {
int len = strlen(arr);
for (int i = 2; i < len; i++) {
if ((arr[i] > 'f' && arr[i] <= 'z') || (arr[i] > 'F' && arr[i] <= 'Z')) {
return 0;
}
}
}
return 1;
}
int main(int argc, const char * argv[])
{
float x;
char input[30];
scanf("%s", input);
printf("%s", input);
return 0;
}
If somebody could also tell me the basics of what '%x' means i would really appreciate it. From what I understand it lets me collect numbers in hexadecimal form, but can i store them in ints and floats? Thank you very much for your help.
--Edit: Extra code for floris. I'm trying to solve this problem without using any extra libraries, so you can't use the stdint lib.
char input[30];
scanf("%s", input);
if(check_if_good(input)){ //Ignore this if-statement.
printf("Input is in hex form");
}
int num = convert_hex_string(input); // this function works perfectly. It return the int form of the hex.
double f = *((double*)&num);
printf("%f\n", f);
If you actually want to know what floating point number is represented by a particular hex string, you can convert the string to an integer, then look at the address pretending that it contains a floating point number. Here's how that would work:
#include <stdint.h>
#include <stdio.h>
int main(void) {
char myString[]="0x3f9d70a4";
uint32_t num;
float f;
sscanf(myString, "%x", &num); // assuming you checked input
f = *((float*)&num);
printf("the hexadecimal 0x%08x becomes %.3f as a float\n", num, f);
}
This produces as output
the hexadecimal 0x3f9d70a4 becomes 1.230 as a float
As expected. See my answer to your other question about a related topic for more details.
It should also be easy to see how you can do the above in reverse - start with a floating point number, and get the hexadecimal representation.
If you are permitted to use library functions, try atoi(arr) or sscanf(arr+2, "%x", &num)
If you want to parse the string manually, think about how you'd convert a decimal number. For example, converting "2987" to an integer...
int n = 0;
n += 1000 * 2;
n += 100 * 9;
n += 10 * 8;
n += 1 * 7;
Now apply the technique to hexadecimal. Here is a code snippet to do a single ascii character:
int char_to_int(char c) {
if (c >= '0' && c <= '9') return c - '0';
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
return 0; /* oops, something else... */
}
You'll need to use either multiplication or bit operations. After you do your bounds/hex checking you described, do something like this:
float x = 0;
for(i=0;i<8;i++)
{
x += getDecimalValue(inputArray[i+2]) << (4*(7-i))
}
This is untested code & you will need to do the conversion from char to decimal value (A=10, B=11 ect). That bitwise operation is the same as multiplying the decimal equivalent of the hex character by 2^numberOfBits. This answer is assuming the leftmost hex is the most significant (Big endian), reverse the operation for little endianess.
If the input is in the form: "0x......" then
float f;
long l;
l = strtol(input, (char**)NULL, 16);
f = (float)l;
printf("%f", f);
valter
Related
I am writing a program that converts a given bit string (up to 32-bits) into decimal assuming the input is given in unsigned magnitude and two's complement. I am reading each bit in from the user one char at a time and attempting to store it into an array, but the array doesn't have a required size. Is there a way to get the array to go through the loop without the array size being known? I also am trying to figure out a way to not use the pow and multiplication functions. I am posting my code below, if you have any ideas please
#include "stdio.h"
#include "math.h"
#define MAX_BITS 32
#define ENTER '\n'
#define NUMBER_TWO 2
int main()
{
int unsignedMag;
int twosComp;
int negation[n];
int bitStore[n];
char enter;
//Input from the User
printf("Enter up to 32 bits (hit 'enter' to terminate early): ");
//Reads the first bit as a character
char bit = getchar();
while (getchar != enter) {
bit = bit - '0';
scanf("%c", &bitStore[bit]);
getchar();
}
//Terminates if user hits enter
if (bit == enter) {
return 0;
}
//Continue through code
else {
//Loop to calculate unsigned magnitude
for (int i = 0; i < bitStore[i]; i++) {
unsignedMag = unsignedMag + (bitStore[i] * pow(NUMBER_TWO, i));
}
//Loop to calculate complete negation
for (int j = 0; j < bitStore; j++) {
negation[j] = ~bitStore[j]
}
negation = negation + 1;
for (int l = 0; l < negation; l++) {
twosComp = twosComp + (negation[l] * pow(NUMBER_TWO, l));
}
}
return 0;
}
"Is there a way to get the array to go through the loop without the array size being known?"
No. Array sizes are fixed at the point the array is declared and the size is knownable: e.g. #Observer
size_t size = sizeof bitStore/sizeof bitStore[0];
Instead, since code has "given bit string (up to 32-bits) ", define the array as size 32 (or 33 is a string is desired).
Keep track of how much of the array was assigned.
//int bitStore[n];
int bitStore[MAX_BITS];
int count = 0;
// char bit = getchar();
int bit = getchar(); // Use `int` to account for potentially 257 different values
//while (getchar != enter) {
while (count < MAX_BITS && (bit == '0' || bit == '1')) {
bit = bit - '0';
// Do not read again, instead save result.
//scanf("%c", &bitStore[bit]);
bitStore[count++] = bit;
// getchar();
bit = getchar();
}
to not use the pow and multiplication functions.
Simply add or multiply by 2 via a shift. It is unclear why OP has a goal of not using "multiplication". I see little reason to prohibit *. A good compiler will emit efficient code when the underlying multiplication is expensive as *2 is trivial to optimize.
// int unsignedMag;
unsigned unsignedMag = 0; // initialize
// for (int i = 0; i < bitStore[i]; i++) {
for (int i = 0; i < count; i++) {
// preferred code, yet OP wants to avoid * for unclear reasons
// unsignedMag = unsignedMag*2 + bitStore[i];
unsignedMag = unsignedMag + unsignedMag + bitStore[i];
}
pow() is good to avoid for many reasons here. Most of all, using double math for an integer problem runs into precision issues with wide integers.
converts a given bit string (up to 32-bits) into decimal
Note that a bitStore[] array is not needed for this task. Simply form unsignedMag as data is read.
I wrote this function from a pseudocode I found, which should convert decimal input into hexadecimal number. Well it does that, but in incorrect order, like for example, for decimal number 195 I get 3C, insted of C3.
int temp=0;
int i=0;
while(decimal!=0)
{
temp = decimal % 16;
if( temp < 10)
temp =temp + 48;
else
temp = temp + 55;
array[i++]= temp;
decimal = decimal / 16;
}
save yourself some time like this
#include <stdio.h>
// ...
sprintf(hexStr,"%X",decimal); // or, "%#X" if you want prefix
unless, this is homework for a programming class. in which case you should really just work it out on whiteboard or paper, i'm sure you'll see your mistake.
I need to decompose a decimal part of a number in single digits, but I need to get the most obvious representation. Here is my code, to be clearer :
#include <stdio.h>
void main(){
double value = 0.123;
int decim_tab[6];
int decimal;
int i;
for (i = 0; i < 6; ++i) {
value *= 10;
decimal = (int)value;
decim_tab[i] = decimal;
value -= decimal;
}
for (i = 0; i < 6; ++i)
print("%d\n", decim_tab[i]);
}
The output I need is :
1
2
3
0
0
0
But I get :
1
2
2
9
9
9
EDIT
A solution I found is to add a small delta to the value in order to force the shortest representation :
#include <stdio.h>
void main(){
double value = 0.123;
int decim_tab[6];
int decimal;
int i;
value += 0.000000001
for (i = 0; i < 6; ++i) {
value *= 10;
decimal = (int)value;
decim_tab[i] = decimal;
value -= decimal;
}
for (i = 0; i < 6; ++i)
print("%d\n", decim_tab[i]);
}
I would be happy to find a better way, any suggestions ?
The reason you get unexpected output is that decimal fractions cannot always be exactly represented using (most common) base two floating point numbers. Using printf("%.20f", value); after your assignment of value you will see that the value 0.123 is actually being stored as 0.12299..., which is why you receive that output.
If you only need to print out six digits, you can use string formatting of floating point numbers:
#include <stdio.h>
#include <stdlib.h>
int main(){
double value = 0.123;
char *s = malloc(9);
sprintf(s++, "%.6f", value);
while(*s++){
putchar(*s);
putchar('\n');
}
}
EDIT: The code in my answer is very specific to the example you gave, so when using it be aware that I made some assumptions, e.g. your value will never have more than one digit before the decimal point.
If you want 6 decimal places, you should add 0.0000005 (ie 0.5e-6) to round the value to the nearest place. This method will work for positive numbers, first extract the sign, then work on the absolute value.
Floating point numbers are not exact value representation. Here's a simple sample:
double a = 0.15 + 0.15; // 0.15 + 0.15 == 0.3, right?
double b = 0.1 + 0.2; // 0.1 + 0.2 == 0.3, right?
if (a == b) {
printf("Equal\n");
} else {
printf("Unequal\n");
}
What will that print? Equal? Are you sure? Try it yourself:
http://rextester.com/VZOZ1043
It prints Unequal, that's because there are some numbers that floating point can't represent exactly and that's something you always need to keep in mind when doing floating point math. Also there is rounding involved in many operations, so the results of math operations are as good as possible but not always "exact", there's a tiny error that can also sum up if you run multiple operations.
double value = 0.123;
// Assuming none of your numbers has more than 58 digits,
// one period and one termination char.
char buffer[60];
// Print the number to the buffer.
// Missing: Error checking if it did fit!
snprintf(buffer, sizeof(buffer), "%f", value);
// Find the period or end of string
int idx = 0;
for (; buffer[idx] && buffer[idx] != '.'; idx++);
// Print anything after the period till
// the end of the string
if (buffer[idx] == '.') {
for (idx++; buffer[idx]; idx++) {
printf("%c\n", buffer[idx]);
}
}
Test it: http://rextester.com/CYDQO24769
I'm building a program in C that can get powers of 2. The user inputs the value of n, and the program calculates 2^n.
Here's the code.
The problem comes when I input 100
What I am getting:
1,267,650,600,228,229,400,000,000,000,000
What I should get
1,267,650,600,228,229,401,496,703,205,376
It has to be coded entirely in ANSI C. Any ideas on how to increase the precision? The maximum value of N has to be 256 (256 bits, I imagine, which means the maximum output should be 2^256).
What I'm lacking here is precision, and I don't know how to fix that. Any ideas?
I think it's easiest if you work in base 10 from the start. This is because while calculating powers of 2 in binary is trivial, the conversion back to base 10 is a lot harder.
If you have an array of base 10 digits1, you only need to implement base 10 addition with carry to be able to multiply by 2 (by adding the number to itself). Do that n times in a loop and you have your answer.
If you wish to support higher exponents, you can also look into implementing exponentiation by squaring, but that's harder, since you'll need general multiplication, not just by 2 for that.
1 Tip: It's more convenient if you store the digits in reverse order.
Here is my quick and dirty implementation of hammar's approach., storing the decimal number as a C string with the digits in reverse order.
Run the code on ideone
void doubleDecimal(char * decimal)
{
char buffer[256] = "";
char c;
unsigned char d, carry = 0;
int i = 0;
while (c = decimal[i])
{
d = 2 * (c - '0') + carry;
buffer[i] = (d % 10) + '0';
carry = d / 10;
i++;
}
if (carry > 0)
buffer[i++] = (carry % 10) + '0';
buffer[i] = '\0';
strncpy(decimal, buffer, 256);
}
void reverse(char * str)
{
int i = 0;
int j = strlen(str) - 1;
while (j > i)
{
char tmp = str[i];
str[i] = str[j];
str[j] = tmp;
i++;
j--;
}
}
int main(void)
{
char decimal[256] = "1";
int i;
for (i = 0; i < 100; i++)
doubleDecimal(decimal);
reverse(decimal);
printf("%s", decimal);
return 0;
}
Output:
1267650600228229401496703205376
double is a (probably) 64bit value. You can't store 256 bits of precision in 64 bits. The reason that you are getting a number that is sort of close is because floating point numbers are stored with varying precision -- not all sequential numbers can be represented, but you can represent very large numbers. Pretty useless in this case.
What you want is either to use an arbitrary precision library or, since this is probably homework, you are expected to write your own.
A typical double, using 64-bit IEEE 754, has about 51 bits precision, IIRC.
Most probably the point of supporting exponents up to 256 is to exceed that precision, and also the precision of a long double or long long, so that you have to do things yourself.
As a homework exercise, then,
Store decimal digit values in an array + a digit count
Implement doubling of the value in such array + count
Start with 1 and double value appropriate number of times.
A few things you'll want to think about to solve this:
You are only dealing with integers so you should use an integer
representation (you will need to roll your own because you can't use
long long which is "only" 64 bits long).
Powers of 2 you say -how convenient - computers store numbers using powers of 2 (you'll
only need to use shift operations and bit fiddling .... no
multiplications will be needed).
How can you convert a base 2 number to a base 10 number for display purposes (think of division and outputting one number at a time (think about what a hardware divisor does in order to get the bit manipulations correct).
You can't the store 256 bits of precision in 64 bits. Reason that you are getting a number to close is because floating point numbers are stored with varying precision. To all sequential numbers can be represented, but you can represent very large numbers. Pretty useless in this case.
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//constants
#define MAX_DIGITS 1000
//big integer number struct
struct bigint {
char Digits[MAX_DIGITS];
};
//assign a value
void assign(struct bigint* Number,int Value) {
if (Value!=1) {
printf("Can not assign value other than 1\n");
exit(0);
}
memset(Number,0,sizeof(bigint));
Number->Digits[0] = Value;
}
//multiply the big integer number with value
void multiply(struct bigint* Number,int Value) {
int Digit,New_Digit;
int Carry = 0;
for (int Index=0; Index<MAX_DIGITS; Index++) {
Digit = Number->Digits[Index];
New_Digit = Digit*Value%10;
if (New_Digit+Carry<10) {
New_Digit = New_Digit+Carry;
Carry = Digit*Value/10;
}
else {
New_Digit = (New_Digit+Carry)%10;
Carry = (Digit*Value/10)+1;
}
//set the new digit
Number->Digits[Index] = New_Digit;
}//for loop
}
//print out the value of big integer type
void print(struct bigint* Number) {
int Index = MAX_DIGITS-1;
while (Number->Digits[Index]==0 && Index>=0)
Index--;
//the big integer value is zero
if (Index==-1) {
printf("0");
return;
}
while (Index>=0) {
printf("%u",Number->Digits[Index]);
Index--;
}
}
//main programme entry point
int main(int Argc,char** Args) {
int Power = 100;
struct bigint Number;
//assign the initial value
assign(&Number,1);
//do the multiplication
for (int Index=0; Index<Power; Index++)
multiply(&Number,2);
//print result
print(&Number);
getch();
}
//END-OF-FILE
I'd like the following code to work:
double num = 31415; /* num will never have a decimal part */
/* ... code here so that we can now say */
printf("%d", num_array[0] == 3 && num_array[1] == 1 && num_array[4] == 5); //1
I realize it's trivial to do this with ints (just int i=0; while(num>0) numarr[size-++i] = num%10, num/=10; where size is predetermined to be the number of digits in the number), but that obviously won't work for floats/doubles because you can't mod one floats.
And yes, I need to use floats/doubles, despite not using the floating point section (it's an exercise).
And I have figured out how to determine the number of digits in a double, using floor().
/* n > 0, n=floor(n) */
int numdigits(double n){
int i = 0;
while (n >0)
n = floor(n/10), i++;
return i;
}
Look up fmod. The number of digits will probably be easier to compute using log10.
It's probably easiest to just convert it to a string:
char* str = malloc(num_digits+1);
snprintf(str, num_digits+1, "%f", num);
Indexing into str will give you each digit as an ASCII value, so you'll need to subtract '0' to get the actual numeric value:
str[0] - '0' == 3;
str[1] - '0' == 1;
str[2] - '0' == 4;
...
Apart from fmod(), you could also cast to a int64_t or long long int, and use % as before. If the range is less than 10 digits, you could use a int32_t.