Are multiples of 0.25 exactly representable as double? - c

I have the following code for finding quartiles:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
double qrt[3];
double *value;
int count;
} t_data;
static void set_qrt(t_data *data, int qrt)
{
int n, e;
double d;
d = qrt * 0.25 * data->count + 0.5;
n = (int)d;
e = n != d;
data->qrt[qrt - 1] = data->value[n - 1];
if (e) {
data->qrt[qrt - 1] += data->value[n];
data->qrt[qrt - 1] *= 0.5;
}
}
static void set_qrts(t_data *data)
{
set_qrt(data, 2);
if (data->count > 1) {
set_qrt(data, 1);
set_qrt(data, 3);
} else {
data->qrt[0] = 0.0;
data->qrt[2] = 0.0;
}
}
static int comp(const void *pa, const void *pb)
{
const double a = *(const double *)pa;
const double b = *(const double *)pb;
return (a > b) ? 1 : (a < b) ? -1 : 0;
}
int main(void)
{
double values[] = {3.7, 8.9, 7.1, 5.4, 1.2, 6.8, 4.3, 2.7};
t_data data;
data.value = values;
data.count = (int)(sizeof(values) / sizeof(double));
qsort(data.value, data.count, sizeof(double), comp);
set_qrts(&data);
printf("Q1 = %.1f\nQ2 = %.1f\nQ3 = %.1f\n", data.qrt[0], data.qrt[1], data.qrt[2]);
}
Is
d = qrt * 0.25 * data->count + 0.5;
n = (int)d;
e = n != d;
guaranteed to work as expected? (e == isinteger(d))

Numbers 0.5, 0.25, 0.125 and so on represent negative powers of two, and therefore are representable exactly in IEEE 754 types. Using these numbers does not result in representation errors.

The values 0.5 and 0.25 themselves will be exact. The intermediate values of your calculation may or may not be, depending on their range. IEEE doubles have a 52-bit mantissa, so they will exactly represent to the 0.25 numbers that need 50 bits or fewer in the mantissa, which is about 15 decimal digits.
So if you add 0.25 to 100000000000000 (10^14), you'll get 100000000000000.25. But if you add 0.25 to 10000000000000000 (10^16), you'll lose the fraction.

dasblinkenlight is absolutely correct. Double/float and integer types are stored differently according to IEEE754. Watch this for an easy tutorial if you are curious about it.

The double precision floating point format has 53 bits in its manitissa of which one is implicit. This means that it can represent all positive and negative integers in the range 2^0 to 2^53-1.
0 (zero) is a special case which has its own format.
When it comes to a 0.25 spacing the range is straight-forwardly calculated to be 2^-2 to 2^51-0.25. This means that quite a few but by no means all multiples of 0.25 are exactly representable in the double precision format, just as a quite a few but not all integers are exactly representable.
So if you have an exactly representable spacing of 2^x the representable range is 2^x to 2^(53+x)-2^x.

Related

Is it possible to replace a double number and write the program using only integers in C, with the same output?

Is it possible to write a program like this, using only the integer type and the standard library <stdio.h> in C? The output of the remainder must be displayed as a decimal number with two numbers behind the comma.
#include <stdio.h>
int num1 = 0;
int num2 = 1;
int num3 = 6;
int num4 = 3;
int num5 = 7;
int num6 = 3;
int num7 = 9;
int num8 = 8;
int sum, product, Result;
double division;
int main()
{
sum = num1 + num2 + num3 + num4;
product = num5 * num6 * num7;
Result = ((++product) - (sum++)) * sum;
int Integer_division = Result / (num8+ 1);
int Remainder = Result % (num8+ 1);
double division = Result / (num8+ 1);
printf("Result = %d\n", Result);
printf("Integer division = %d\n", Integer_division);
printf("Remainder = %d\n", Remainder);
printf("Division = %.02f\n", division);
return 0;
}
I was thinking about splitting it into two halves and printing it with a comma in between(%d.%d)
but that sounds like my last resort...
Thanks in advance.
To print floating-point like text from integers requires the sign, while-number part and the fraction part
char *sign = Result<0 ? "-":"";
int whole = abs(Integer_division);
char decimal_point = ','; // behind the comma.
int hundredths = abs(Remainder *100/(num8+ 1)); // Convert fraction to
1/100ths
// now print it
printf("%s%d%c%02d", sign, whole, decimal_point, hundredths);
Yet this displays only a truncated result. To round is work.
The usual way to mimic floating point output using integers it to consider the value as a fraction of 2 integer parts: numerator, denominator that needs scaling (e.g. x100 for .00 display) . For simplicity, assume denominator > 0.
First step is rounding due to finite display precision. Since the next step will involve an integer divide "truncate toward zero" and floating-point like display is usually "round to nearest", code needs to add a signed, unscaled 0.5 or one-half the denominator.
For simplicity, assume denominator > 0 and is odd so we can avoid half-way cases (even more work). Also assume no int overflow to avoid more work.
int numerator = Result;
int denominator = num8+ 1;
int scale = 100; // to print to 0.xx
int scaled_numerator = numerator * scale;
int scaled_half = denominator / 2;
if (scaled_numerator < 0) scaled_half = -scaled_half;
int rounded_scaled_numerator = scaled_numerator + scaled_half;
Now divide
int scaled_value = rounded_scaled_numerator/denominator;
char *sign = scaled_value<0 ? "-":"";
scaled_value = abs(scaled_value);
int whole = scaled_value / scale;
char decimal_point = ',';
int hundredths = scaled_value % scale;
printf("%s%d%c%02d", sign, whole, decimal_point, hundredths);

Getting Garbage value when converting Float to string?

I am getting garbage value when converting float to string. I cant use sprintf because it takes more memory and PIC24 microcontroller ram size is very low (128kb). When converting it gives some garbage values as ?39.88 like this What may be the problem . I am posting my code...
#include<stdio.h>
#include<string.h>
#include<math.h>
float Distance=0;
char str[15];
unsigned char *ftos(float f,int precision)
{
memset(str,0,sizeof(str));
float ff;
ff = f;
int a,b,c,k,l=0,m,i=0;
// check for negative float
if(f<0.0)
{
str[i++]='-';
f*=-1;
}
a=f; // extracting whole number
f-=a; // extracting decimal part
k = precision;
// number of digits in whole number
while(k>0)
{
l = pow(10.0f,k);
m = a/l;
if(m>0)
{
break;
}
k--;
}
// number of digits in whole number are k+1
/*
extracting most significant digit i.e. right most digit , and concatenating to string
obtained as quotient by dividing number by 10^k where k = (number of digit -1)
*/
for(l=k+1;l>0;l--)
{
b = pow(10.0f,l-1);
c = a/b;
str[i++]=c+48;
a%=b;
}
str[i++] = '.';
/* extracting decimal digits till precision */
for(l=0;l<precision;l++)
{
f*=10.0;
b = f;
str[i++]=b+48;
f-=b;
}
str[i]='\0';
return str;
}
void distance(float lat1, float lon1, float lat2, float lon2)
{
float dlon=0,dlat=0,a=0,c=0,dist=0;
dlon = (lon2 - lon1) * (M_PI / 180.0);
dlat = (lat2 - lat1) * (M_PI / 180.0);
a = pow(sin(dlat/2.0), 2) + cos(lat1*(M_PI / 180.0)) * cos(lat2*(M_PI / 180.0)) * pow(sin(dlon/2.0), 2);
c = 2 * atan2(sqrt(a), sqrt(1-a));
dist = 6367 * c;
Distance += dist;
}
int main()
{
distance(13.00659,80.121212,13.69898,80.256987);
printf("%s\n",ftos(Distance,6));
}
when i print the distance value after conversion it gives some garbage value... why?

Why can these be declared as integers?

In a program that seems to work well I have the following declarations:
#include <stdio.h>
#include "system.h"
signed char input[4]; /* The 4 most recent input values */
char get_q7( void );
void put_q7( char );
void firFixed(signed char input[4]);
const int c0 = (0.0299 * 128 + 0.5); /* Converting from float to Q7 is multiplying by 2^n i.e. 128 = 2^7 since we use Q7 and round to the nearest integer*/
const int c1 = (0.4701 * 128 + 0.5);
const int c2 = (0.4701 * 128 + 0.5);
const int c3 = (0.0299 * 128 + 0.5);
const int half = (0.5000 * 128 + 0.5);
enum { Q7_BITS = 7 };
void firFixed(signed char input[4])
{
int sum = c0*input[0] + c1*input[1] + c2*input[2] + c3*input[3];
signed char output = (signed char)((sum + half) >> Q7_BITS);
put_q7(output);
}
int main(void)
{
int a;
while(1)
{
for (a = 3 ; a > 0 ; a--)
{
input[a] = input[a-1];
}
input[0]=get_q7();
firFixed(input);
}
return 0;
}
But I don't understand how it's possibl to declare a fractional number as int which is done with the constants. It's supposed to be Q7 notation but why is it done this way and how can the compiler accept an int that is a fractional number? Will it simply take the integer part of the fraction and if so why isn't a cast required?
When a floating point value is converted to an integer, it's truncated. That means that all digits after the decimal point is simply removed. E.g. 12.34 becomes 12, and 12.99 also becomes 12. There is no rounding done.
That is what the + 0.5 part does in the initializations. It's simply a way to convert a floating point value to integer with rounding. For example, 0.0299 * 128 is 3.8272 which truncated would be 3. But with the + 0.5 it's 4.3272 which truncated becomes 4, which is the rounded value of 3.8272.
There may however still be problems, and you might want to read What Every Computer Scientist Should Know About Floating-Point Arithmetic to learn more.
Cast required only in case of type promotion not in case of type truncation.

Manually implementing a rounding function in C

I have written a C program (which is part of my project) to round off a float value to the given precision specified by the user. The function is something like this
float round_offf (float num, int precision)
What I have done in this program is convert the float number into a string and then processed it.
But is there a way to keep the number as float itself and implement the same.
Eg. num = 4.445 prec = 1 result = 4.4
Of course there is. Very simple:
#include <math.h>
float custom_round(float num, int prec)
{
int trunc = round(num * pow(10, prec));
return (float)trunc / pow(10, prec);
}
Edit: it seems to me that you want this because you think you can't have dynamic precision in a format string. Apparently, you can:
int precision = 3;
double pie = 3.14159265358979323648; // I'm hungry, I need a double pie
printf("Pi equals %.*lf\n", precision, pie);
This prints 3.142.
Yes:
float round_offf(float num, int precision)
{
int result;
int power;
power = pow(10, precision + 1);
result = num * power;
if ((result % 10) > 5)
result += 10;
result /= 10;
return ((float)result / (float)power);
}

How can I convert a float/double to ASCII without using sprintf or ftoa in C?

How can I convert a float/double to ASCII without using sprintf or ftoa in C?
I am using an embedded system.
The approach you take will depend on the possible range of values. You certainly have some internal knowledge of the possible range, and you may only be interested in conversions within a more narrow range.
So, suppose you are only interested in the integer value. In this case, I would just assign the number to an int or long, at which point the problem becomes fairly obvious.
Or, suppose the range won't include any large exponents but you are interested in several digits of fraction. To get three digits of fraction, I might say int x = f * 1000;, convert x, and then insert the decimal point as a string operation.
Failing all of the above, a float or double has a sign bit, a fraction, and an exponent. There is a hidden 1 in the fraction. (The numbers are normalized until they have no leading zeroes, at which point they do one more shift to gain an extra bit of precision.) The number is then equal to the fraction (plus a leading '1') * 2 ** exponent. With essentially all systems using the IEEE 754 representation you can just use this Wikipedia IEEE 754 page to understand the format. It's not that different from just converting an integer.
For single precision, once you get the exponent and fraction, the valueNote 1 of the number is then (frac / 223 + 1) * 2exp, or frac * 2exp - 23 + 2exp.
Here is an example that should get you started on a useful conversion:
$ cat t.c
#include <stdio.h>
void xconvert(unsigned frac)
{
if (frac) {
xconvert(frac / 10);
printf("%c", frac % 10 | '0');
}
}
void convert(unsigned i)
{
unsigned sign, exp, frac;
sign = i >> 31;
exp = (i >> (31 - 8)) - 127;
frac = i & 0x007fffff;
if (sign)
printf("-");
xconvert(frac);
printf(" * 2 ** %d + 2 ** %d\n", exp - 23, exp);
printf("\n");
}
int main(void)
{
union {
float f;
unsigned i;
} u;
u.f = 1.234e9;
convert(u.i);
return 0;
}
$ ./a.out
1252017 * 2 ** 7 + 2 ** 30
Note 1. In this case the fraction is being converted as if the binary point was on the right instead of the left, with compensating adjustments then made to the exponent and hidden bit.
#include<stdio.h>
void flot(char* p, float x)
{
int n,i=0,k=0;
n=(int)x;
while(n>0)
{
x/=10;
n=(int)x;
i++;
}
*(p+i) = '.';
x *= 10;
n = (int)x;
x = x-n;
while((n>0)||(i>k))
{
if(k == i)
k++;
*(p+k)='0'+n;
x *= 10;
n = (int)x;
x = x-n;
k++;
}
/* Null-terminated string */
*(p+k) = '\0';
}
int main()
{
float x;
char a[20]={};
char* p=&a;
printf("Enter the float value.");
scanf("%f",&x);
flot(p,x);
printf("The value=%s",p);
getchar();
return 0;
}
Even in an embedded system, you'd be hard pressed to beat the performance of ftoa. Why reinvent the wheel?

Resources