This simple function tells you how many bits of precision is long double
in your environment.
Introduction:
Floating-point numbers on most platforms are encoded using IEEE 754.
-
float
is usually 32-bit IEEE 754 (a.k.a.single precision
). -
double
is usually 64-bit IEEE 754 (a.k.a.double precision
).
But what about long double?
Well, the precision of long double
strongly depends on the platform and compiler. It usually is 64-bit, 80-bit, or 128-bit.
The function in this kumite, i.e. get_long_double_precision()
, will return the number of bits of precision of long double
.
For more info
#include <stdlib.h> // size_t
#include <stdint.h> // uint8_t, uint16_t
uint16_t get_long_double_precision(void);
uint8_t is_big_endian(void);
uint16_t get_long_double_precision(void) {
size_t ldsize = sizeof(long double);
uint8_t bigendian = is_big_endian();
long double test = -0.0L;
uint8_t* test_bytes = (uint8_t*) &test;
uint16_t res = 0;
for (size_t i = 0; i < ldsize; i += 1) {
size_t offset = (bigendian == 0) ? i : (ldsize - 1 - i);
res += 8;
if (test_bytes[offset] == 0x80) {
break;
}
}
return res;
}
// utility function: returns 0x01 in case the current platform is big endian,
// otherwise returns 0x00
uint8_t is_big_endian(void) {
uint16_t test = 0x0100;
return ((uint8_t*) &test)[0];
}
#include <criterion/criterion.h>
#include <stdint.h> // uint16_t
#include <inttypes.h> // PRIu16
#include <stdio.h> // printf
uint16_t get_long_double_precision(void);
Test(test, test) {
uint16_t ldprec = get_long_double_precision();
printf("'long double' precision is %" PRIu16 " bits\n", ldprec);
}
Here's an algorithm to simplify a fraction (i.e. reduce a fraction to its lowest terms). It is written in Javascript for simplicity, but it's easily translatable to any programming language.
// e.g.:
// simplify( 15, 5) == [ 3, 1]
// simplify(-50, 20) == [- 5, 2]
// simplify( 20, - 2) == [-10, 1]
// simplify(- 6, - 3) == [ 2, 1]
// simplify(- 0, 3) == [ 0, 1]
// simplify( 0, 0) == undefined
// simplify( 5, - 0) == undefined
function simplify(n, d){
if (d === 0){
return undefined;
}
// fraction_sign contains the sign of the fraction (1 if positive, -1 if negative)
const fraction_sign = ((n < 0) ? -1 : 1) * ((d < 0) ? -1 : 1);
// fraction_gcd contains the greatest common divisor of n and d
const fraction_gcd = gcd(Math.abs(n), Math.abs(d));
// we calculate the reduced numerator (it has the same sign as the fraction)
const result_n = fraction_sign * Math.abs(n) / fraction_gcd;
// we calculate the reduced denominator
const result_d = Math.abs(d) / fraction_gcd;
return [result_n, result_d];
}
// gcd(x, y) calculates the greatest common divisor of x and y
// x and y must be non-negative integers
// USED ALGORITHM: binary method
// BASED ON: https://en.wikipedia.org/wiki/Binary_GCD_algorithm
function gcd(x, y){
if (x === y){
return x;
}
if (x === 0){
return y;
}
if (y === 0){
return x;
}
if (x % 2 === 0){
if (y % 2 === 1){
return gcd(x >> 1, y);
}
else {
return gcd(x >> 1, y >> 1) << 1;
}
}
if (y % 2 === 0){
return gcd(x, y >> 1);
}
if (x > y){
return gcd((x - y) >> 1, y);
}
return gcd((y - x) >> 1, x);
}
describe("Examples", function(){
it("Example #1", function(){
console.log("15 / 5 == 3 / 1");
Test.assertDeepEquals(simplify(15, 5), [3, 1]);
});
it("Example #2", function(){
console.log("-50 / 20 == -5 / 2");
Test.assertDeepEquals(simplify(-50, 20), [-5, 2]);
});
it("Example #3", function(){
console.log("20 / -2 == -10 / 1");
Test.assertDeepEquals(simplify(20, -2), [-10, 1]);
});
it("Example #4", function(){
console.log("-6 / -3 == 2 / 1");
Test.assertDeepEquals(simplify(-6, -3), [2, 1]);
});
it("Example #5", function(){
console.log("-0 / 3 == 0 / 1");
Test.assertDeepEquals(simplify(-0, 3), [0, 1]);
});
it("Example #6", function(){
console.log("0 / 0 == undefined");
Test.assertEquals(simplify(0, 0), undefined);
});
it("Example #7", function(){
console.log("5 / -0 == undefined");
Test.assertEquals(simplify(5, -0), undefined);
});
});