I strongly recommend that you don't use floating point types with currency calculations.
Because of the nature of floating point implementation, most values aren't exact and due to rounding, some basic mathematical properties (i.e: commutative property) aren't valid. Example:
Code:
#include <stdio.h>
#define SHOW_RESULT(c) \
printf("[%s]\n", ((c))?"yes":"no")
void testfp1 ( void )
{
double x = 1.2;
printf ( "x = 1.2 - 0.4 - 0.4 - 0.4; x = 0.0? " );
x -= 0.4;
x -= 0.4;
x -= 0.4;
/* x should be 0.0, right!? Wrong! */
SHOW_RESULT ( x == 0.0 );
}
void testfp2 ( void )
{
double x;
double y;
printf ( "x = (0.1 + 0.2) + 0.3; y = 0.1 + (0.2 + 0.3); x == y ? " );
x = ( 0.1 + 0.2 ) + 0.3;
y = 0.1 + ( 0.2 + 0.3 );
/* x == y, right? Wrong! */
SHOW_RESULT ( x == y );
}
void testfp3 ( void )
{
double x;
double y;
printf ( "x = (0.1 * 0.2) * 0.3; y = 0.1 * (0.2 * 0.3); x == y? " );
x = ( 0.1 * 0.2 ) * 0.3;
y = 0.1 * ( 0.2 * 0.3 );
/* x == y, right? Wrong! */
SHOW_RESULT ( x == y );
}
void testfp4 ( void )
{
double x;
double y;
printf ( "x = (0.1 + 0.2) * 0.3; y = (0.1 * 0.3) + (0.2 * 0.3); x == y? " );
x = ( 0.1 + 0.2 ) * 0.3;
y = ( 0.1 * 0.3 ) + ( 0.2 * 0.3 );
/* x == y, right? Wrong! */
SHOW_RESULT ( x == y );
}
int main ( void )
{
testfp1();
testfp2();
testfp3();
testfp4();
return 0;
}
Yet... Your code is using the float type (which has 24 bits of precision). To avoid truncation you should use, at least, 'double'.
PS: Avoid using 'long double', since it will use fp87 on Intel platforms...
If you should not use floating point, what to do then? Well... You could use integers working with 'cents' units:
Code:
typedef long long currency_T;
#define FLT2CUR(x) ((x) * 100.0)
The only problem is that you need to do some calculations before and after multiplications and divisions:
Code:
currency_T mulcur(currency_T v1, currency_T v2)
{
// FIXME: You should use greater precision (using compiler/language extensions).
__int128 t = (__int128)v1 * v2;
return t / 100; // don't bother with overflows!
}
currency_T divcur( currency_T v1, currency_T v2 )
{
return ( v1 / v2 ) * 100;
}