Multiplication of fixed point numbers - c

I have a very basic question. In my program, i am doing multiplication of two fixed point numbers, which is given below. My inputs are of Q1.31 format and output also should be of same format. In order to do this, i am storing the result of multiplication in a temporary 64 bit variable and then doing some operations to get the result in required format.
int conversion1(float input, int Q_FORMAT)
{
return ((int)(input * ((1 << Q_FORMAT)-1)));
}
int mul(int input1, int input2, int format)
{
__int64 result;
result = (__int64)input1 * (__int64)input2;//Q2.62 format
result = result << 1;//Q1.63 format
result = result >> (format + 1);//33.31 format
return (int)result;//Q1.31 format
}
int main()
{
int Q_FORMAT = 31;
float input1 = 0.5, input2 = 0.5;
int q_input1, q_input2;
int temp_mul;
float q_muls;
q_input1 = conversion1(input1, Q_FORMAT);
q_input2 = conversion1(input2, Q_FORMAT);
q_muls = ((float)temp_mul / ((1 << (Q_FORMAT)) - 1));
printf("result of multiplication using q format = %f\n", q_muls);
return 0;
}
My question is while converting float input to integer input (and also while converting int output
to float output), i am using (1<<Q_FORMAT)-1 format. But i have seen people using (1<<Q_FORMAT)
directly in their codes. The Problem i am facing when using (1<<Q_FORMAT) is i am getting the
negative of the desired result.
For example, in my program,
If i use (1<<Q_FORMAT), i am getting -0.25 as the result
But, if i use (1<<Q_FORMAT)-1, i am getting 0.25 as the result which is correct.
Where am i going wrong? Do i need to understand any other concepts?

On common platforms, int is a two’s complement 32-bit integer providing 31 digits (plus a 'sign' bit). It's a bit too narrow to represent a Q1.31 number which requires 32 digits (plus a 'sign' bit).
In your example, this is manifesting as effective arithmetic overflow in the expression, 1 << Q_FORMAT.
To avoid this, you need to either use a type providing more digits (e.g. long long) or a fixed-point format requiring fewer digits (e.g. Q1.30). You can use unsigned to fix your example but the result will be a 'sign' bit short of Q2.30.

Related

Largest integer that can be stored in long double

EDIT: After some discussion in the comments it came out that because of a luck of knowledge in how floating point numbers are implemented in C, I asked something different from what I meant to ask.
I wanted to use (do operations with) integers larger than those I can have with unsigned long long (that for me is 8 bytes), possibly without recurring to arrays or bigint libraries. Since my long double is 16 bytes, I thought it could've been possible by just switching type. It came out that even though it is possible to represent larger integers, you can't do operations -with these larger long double integers- without losing precision. So it's not possible to achieve what I wanted to do. Actually, as stated in the comments, it is not possible for me. But in general, wether it is possible or not depends on the floating point characteristics of your long double.
// end of EDIT
I am trying to understand what's the largest integer that I can store in a long double.
I know it depends on environment which the program is built in, but I don't know exactly how. I have a sizeof(long double) == 16 for what is worth.
Now in this answer they say that the the maximum value for a 64-bit double should be 2^53, which is around 9 x 10^15, and exactly 9007199254740992.
When I run the following program, it just works:
#include <stdio.h>
int main() {
long double d = 9007199254740992.0L, i;
printf("%Lf\n", d);
for(i = -3.0; i < 4.0; i++) {
printf("%.Lf) %.1Lf\n", i, d+i);
}
return 0;
}
It works even with 11119007199254740992.0L that is the same number with four 1s added at the start. But when I add one more 1, the first printf works as expected, while all the others show the same number of the first print.
So I tried to get the largest value of my long double with this program
#include <stdio.h>
#include <math.h>
int main() {
long double d = 11119007199254740992.0L, i;
for(i = 0.0L; d+i == d+i-1.0; i++) {
if( !fmodl(i, 10000.0L) ) printf("%Lf\n", i);
}
printf("%.Lf\n", i);
return 0;
}
But it prints 0.
(Edit: I just realized that I needed the condition != in the for)
Always in the same answer, they say that the largest possible value of a double is DBL_MAX or approximately 1.8 x 10^308.
I have no idea of what does it mean, but if I run
printf("%e\n", LDBL_MAX);
I get every time a different value that is always around 6.9 x 10^(-310).
(Edit: I should have used %Le, getting as output a value around 1.19 x 10^4932)
I took LDBL_MAX from here.
I also tried this one
printf("%d\n", LDBL_MAX_10_EXP);
That gives the value 4932 (which I also found in this C++ question).
Since we have 16 bytes for a long double, even if all of them were for the integer part of the type, we would be able to store numbers till 2^128, that is around 3.4 x 10^38. So I don't get what 308, -310 and 4932 are supposed to mean.
Is someone able to tell me how can I find out what's the largest integer that I can store as long double?
Inasmuch as you express in comments that you want to use long double as a substitute for long long to obtain increased range, I assume that you also require unit precision. Thus, you are asking for the largest number representable by the available number of mantissa digits (LDBL_MANT_DIG) in the radix of the floating-point representation (FLT_RADIX). In the very likely event that FLT_RADIX == 2, you can compute that value like so:
#include <float.h>
#include <math.h>
long double get_max_integer_equivalent() {
long double max_bit = ldexpl(1, LDBL_MANT_DIG - 1);
return max_bit + (max_bit - 1);
}
The ldexp family of functions scale floating-point values by powers of 2, analogous to what the bit-shift operators (<< and >>) do for integers, so the above is similar to
// not reliable for the purpose!
unsigned long long max_bit = 1ULL << (DBL_MANT_DIG - 1);
return max_bit + (max_bit - 1);
Inasmuch as you suppose that your long double provides more mantissa digits than your long long has value bits, however, you must assume that bit shifting would overflow.
There are, of course, much larger values that your long double can express, all of them integers. But they do not have unit precision, and thus the behavior of your long double will diverge from the expected behavior of integers when its values are larger. For example, if long double variable d contains a larger value then at least one of d + 1 == d and d - 1 == d will likely evaluate to true.
You can print the maximum value on your machine using limits.h, the value is ULLONG_MAX
In https://www.geeksforgeeks.org/climits-limits-h-cc/ is a C++ example.
The format specifier for printing unsigned long long with printf() is %llu for printing long double it is %Lf
printf("unsigned long long int: %llu ",(unsigned long long) ULLONG_MAX);
printf("long double: %Lf ",(long double) LDBL_MAX);
https://www.tutorialspoint.com/format-specifiers-in-c
Is also in Printing unsigned long long int Value Type Returns Strange Results
Assuming you mean "stored without loss of information", LDBL_MANT_DIG gives the number of bits used for the floating-point mantissa, so that's how many bits of an integer value that can be stored without loss of information.*
You'd need 128-bit integers to easily determine the maximum integer value that can be held in a 128-bit float, but this will at least emit the hex value (this assumes unsigned long long is 64 bits - you can use CHAR_BIT and sizeof( unsigned long long ) to get a portable answer):
#include <stdio.h>
#include <float.h>
#include <limits.h>
int main( int argc, char **argv )
{
int tooBig = 0;
unsigned long long shift = LDBL_MANT_DIG;
if ( shift >= 64 )
{
tooBig = 1;
shift -= 64;
}
unsigned long long max = ( 1ULL << shift ) - 1ULL;
printf( "Max integer value: 0x" );
// don't emit an extraneous zero if LDBL_MANT_DIG is
// exactly 64
if ( max )
{
printf( "%llx", max );
}
if ( tooBig )
{
printf( "%llx", ULLONG_MAX );
}
printf( "\n" );
return( 0 );
}
* - pedantically, it's the number of digits in FLT_RADIX base, but that base is almost certainly 2.

C Provide float with binary bits produces the wrong number

So, in C I am trying to give a floating point variable a number in binary bits (or hexadecimal digits) and then print it out, however it doesn't want to print the number I have calculated by hand or with an online converter.
float x = (float) 0b01000001110010000000000000000000;
or
float x = (float) 0x41C80000;
When printed out using
printf("%f", x);
produces results like this:
1103626240.000000
Instead of the expected 25, due to a sign bit of 0, exponent bit of 131, and a fraction of 1.5625.
Why is this, and how can I get the results I want?
The value 0x41C80000 in hex, is an integer that has the value 1103626240 in decimal. In your code, you are casting this value to a float which gives you this result:
x = 1103626240.000000
A solution for this can be made using a union:
union uint_to_float {
unsigned int u;
float f;
};
union uint_to_float u2f;
u2f.u = 0x41C80000;
printf("x = %f\n", u2f.f);
EDIT:
As mentioned by #chux, using uint32_t from stdint.h, instead of unsigned int is a better solution.

Generic Function To extract Decimal part of a float without Floor() [duplicate]

This question already has answers here:
How to extract the decimal part from a floating point number in C?
(16 answers)
Closed 5 years ago.
I want to split the float number to two separate part as real and non real part.
For example: if x = 45.678, then my function have to give real= 45 and non_real=678. I have tried the following logic.
split ( float x, unsigned int *real, unsigned int *non_real)
{
*real = x;
*non_real = ((int)(x*N_DECIMAL_POINTS_PRECISION)%N_DECIMAL_POINTS_PRECISION);
printf ("Real = %d , Non_Real = %d\n", *real, *non_real);
}
where N_DECIMAL_POINTS_PRECISION = 10000. It would give decimal part till 4 digits, not after.
It works only for specific set of decimal point precision. The code is not generic, it has to work for all floating numbers also like 9.565784 and 45.6875322 and so on. So if anyone could help me on this, it would be really helpful.
Thanks in advance.
Use floor() to find the integer part, and then subtract the integer part from the original value to find the fractional part.
Note: The problem you're most likely having is that some numbers are too large for the integer part to fit in the range of an int.
--Added--
If and only if you are able to assume that an unsigned int is larger than the floating point representation's significand (e.g. 32-bit unsigned int and IEEE standard single-precision floating point with only 23 fractional bits, where "32 < 23" is true); then a number that is too large for an unsigned int can't have any fractional bits. This leads to a solution like:
if(x > UINT_MAX) {
integer_part = x;
fractional_part = 0;
} else {
integer_part = (int)x;
fractional_part = x - integer_part;
}

Converting SIGNED fractions to UNSIGNED fixed point for addition and multiplication

How can we convert floating point numbers to their "fixed-point representations", and use their "fixed-point representations" in fixed-point operations such as addition and multiplication? The result in the fixed-point operation must yield to the correct answer when converted back to floating point.
Say:
(double)(xb_double) + (double)(xb_double) = ?
Then we convert both addends to a fixed point representation (integer),
(int)(xa_fixed) + (int)(xb_fixed) = (int) (xsum_fixed)
To get (double)(xsum_double), we convert (int)(sum_fixed) back to floating point and yield same answer,
FixedToDouble(xsum_fixed) => xsum_double
Specifically, if the range of the values of xa_double and xb_double is between -1.65 and 1.65, I want to convert xa_double and xb_double in their respective 10-bit fixed point representations (0x0000 to 0x03FF)
WHAT I HAVE TRIED
int fixed_MAX = 1023;
int fixed_MIN = 0;
double Value_MAX = 1.65;
double Value_MIN = -1.65;
double slope = ((fixed_MAX) - (fixed_MIN))/((Value_MAX) - (Value_MIN));
int DoubleToFixed(double x)
{
return round(((x) - Value_MIN)*slope + fixed_MIN); //via interpolation method
}
double FixedToDouble(int x)
{
return (double)((((x) + fixed_MIN)/slope) + Value_MIN);
}
int sum_fixed(int x, int y)
{
return (x + y - (1.65*slope)); //analysis, just basic math
}
int subtract_fixed(int x, int y)
{
return (x - y + (1.65*slope));
}
int product_fixed(int x, int y)
{
return (((x * y) - (slope*slope*((1.65*FixedToDouble(x)) + (1.65*FixedToDouble(y)) + (1.65*1.65))) + (slope*slope*1.65)) / slope);
}
And if I want to add (double)(1.00) + (double)(2.00) = which should yield to (double)(3.00),
With my code,
xsum_fixed = DoubleToFixed(1.00) + DoubleToFixed(2.00);
xsum_double = FixedToDouble(xsum_fixed);
I get the answer:
xsum_double = 3.001613
Which is very close to the correct answer (double)(3.00)
Also, if I perform multiplication and subtraction I get 2.004839 and -1.001613, respectively.
HERE'S THE CATCH:
So I know my code is working, but how can I perform addition, multiplication and subtraction on these fixed-point representations without having INTERNAL FLOATING POINT OPERATIONS AND NUMBERS.
So in the code above, the functions sum_fixed, product_fixed, and subtract_fixed have internal floating point numbers (slope and 1.65, 1.65 being the MAX float input). I derived my code by basic math, really.
So I want to implement add, subtract, and product functions without any internal floating point operations or numbers.
UPDATE:
I also found a simpler code in converting fractional numbers to fixed-point:
//const int scale = 16; //1/2^16 in 32 bits
#define DoubleToFixed(x) (int)((x) * (double)(1<<scale))
#define FixedToDouble(x) ((double)(x) / (double)(1<<scale))
#define FractionPart(x) ((x) & FractionMask)
#define MUL(x,y) (((long long)(x)*(long long)(y)) >> scale)
#define DIV(x, y) (((long long)(x)<<16)/(y))
However, this converts only UNSIGNED fractions to UNSIGNED fixed-point. And I want to convert SIGNED fractions (-1.65 to 1.65) to UNSIGNED fixed-point (0x0000 to 0x03FF). How can I do this with the use of this code above? Is the range or number of bits have something to do with the conversion process? Is this code only for positive fractions?
credits to #chux
You can have the mantissa of the floating point representation of your number be equal to its fixed point representation. Since FP addition shifts the smaller operand's mantissa until both operands have the same exponent, you can add a certain 'magic number' to force it. For double, it's 1<<(52-precision) (52 is double's mantissa size, 'precision' is the required number of binary precision digits). So the conversion would look like this:
union { double f; long long i; } u = { xfloat+(1ll<<52-precision) }; // shift x's mantissa
long long xfixed = u.i & (1ll<<52)-1; // extract the mantissa
After that you can use xfixed in integer math (for multiplication, you'd have to shift the result right by 'precision'). To convert it back to double, simply multiply it by 1.0/(1 << precision);
Note that it doesn't handle negatives. If you need them, you'd have to convert them to the complementary representation manually (first fabs the double, then negate the int result if the input was negative).

pow() seems to be out by one here

What's going on here:
#include <stdio.h>
#include <math.h>
int main(void) {
printf("17^12 = %lf\n", pow(17, 12));
printf("17^13 = %lf\n", pow(17, 13));
printf("17^14 = %lf\n", pow(17, 14));
}
I get this output:
17^12 = 582622237229761.000000
17^13 = 9904578032905936.000000
17^14 = 168377826559400928.000000
13 and 14 do not match with wolfram alpa cf:
12: 582622237229761.000000
582622237229761
13: 9904578032905936.000000
9904578032905937
14: 168377826559400928.000000
168377826559400929
Moreover, it's not wrong by some strange fraction - it's wrong by exactly one!
If this is down to me reaching the limits of what pow() can do for me, is there an alternative that can calculate this? I need a function that can calculate x^y, where x^y is always less than ULLONG_MAX.
pow works with double numbers. These represent numbers of the form s * 2^e where s is a 53 bit integer. Therefore double can store all integers below 2^53, but only some integers above 2^53. In particular, it can only represent even numbers > 2^53, since for e > 0 the value is always a multiple of 2.
17^13 needs 54 bits to represent exactly, so e is set to 1 and hence the calculated value becomes even number. The correct value is odd, so it's not surprising it's off by one. Likewise, 17^14 takes 58 bits to represent. That it too is off by one is a lucky coincidence (as long as you don't apply too much number theory), it just happens to be one off from a multiple of 32, which is the granularity at which double numbers of that magnitude are rounded.
For exact integer exponentiation, you should use integers all the way. Write your own double-free exponentiation routine. Use exponentiation by squaring if y can be large, but I assume it's always less than 64, making this issue moot.
The numbers you get are too big to be represented with a double accurately. A double-precision floating-point number has essentially 53 significant binary digits and can represent all integers up to 2^53 or 9,007,199,254,740,992.
For higher numbers, the last digits get truncated and the result of your calculation is rounded to the next number that can be represented as a double. For 17^13, which is only slightly above the limit, this is the closest even number. For numbers greater than 2^54 this is the closest number that is divisible by four, and so on.
If your input arguments are non-negative integers, then you can implement your own pow.
Recursively:
unsigned long long pow(unsigned long long x,unsigned int y)
{
if (y == 0)
return 1;
if (y == 1)
return x;
return pow(x,y/2)*pow(x,y-y/2);
}
Iteratively:
unsigned long long pow(unsigned long long x,unsigned int y)
{
unsigned long long res = 1;
while (y--)
res *= x;
return res;
}
Efficiently:
unsigned long long pow(unsigned long long x,unsigned int y)
{
unsigned long long res = 1;
while (y > 0)
{
if (y & 1)
res *= x;
y >>= 1;
x *= x;
}
return res;
}
A small addition to other good answers: under x86 architecture there is usually available x87 80-bit extended format, which is supported by most C compilers via the long double type. This format allows to operate with integer numbers up to 2^64 without gaps.
There is analogue of pow() in <math.h> which is intended for operating with long double numbers - powl(). It should also be noticed that the format specifier for the long double values is other than for double ones - %Lf. So the correct program using the long double type looks like this:
#include <stdio.h>
#include <math.h>
int main(void) {
printf("17^12 = %Lf\n", powl(17, 12));
printf("17^13 = %Lf\n", powl(17, 13));
printf("17^14 = %Lf\n", powl(17, 14));
}
As Stephen Canon noted in comments there is no guarantee that this program should give exact result.

Resources