]> git.tdb.fi Git - libs/datafile.git/blob - source/binfloat.cpp
Use custom encoding for floats in binary format
[libs/datafile.git] / source / binfloat.cpp
1 #include <cmath>
2 #include "binfloat.h"
3
4 using namespace std;
5
6
7 namespace Msp {
8 namespace DataFile {
9
10 BinFloat BinFloat::explode(UInt64 value, const Bits &bits)
11 {
12         UInt64 mantissa_mask = (UInt64(1)<<bits.mantissa)-1;
13         int exponent_mask = (1<<bits.exponent)-1;
14
15         BinFloat bf;
16         // Extract biased exponent and sign
17         bf.exponent = (value>>bits.mantissa)&exponent_mask;
18         bf.sign = value>>(bits.mantissa+bits.exponent);
19         bf.infinity = (bf.exponent==exponent_mask);
20
21         if(bf.exponent==0 || bf.infinity)
22                 // Zeroes and infinities have zero mantissa
23                 bf.mantissa = 0;
24         else
25         {
26                 // Extract mantissa, add the implied one and align it to high bits
27                 bf.mantissa = (value&mantissa_mask) | (UInt64(1)<<bits.mantissa);
28                 bf.mantissa <<= 63-bits.mantissa;
29         }
30
31         // Unbias the exponent
32         bf.exponent -= exponent_mask>>1;
33
34         return bf;
35 }
36
37 UInt64 BinFloat::compose(const Bits &bits)
38 {
39         UInt64 mantissa_mask = (UInt64(1)<<bits.mantissa)-1;
40         int exponent_mask = (1<<bits.exponent)-1;
41
42         int biased_exponent = exponent+(exponent_mask>>1);
43         // Shift down and round the mantissa
44         UInt64 rounded_mantissa = ((mantissa>>(62-bits.mantissa))+1)>>1;
45         // If the integer part is greater than one, we need to use a higher exponent
46         if((rounded_mantissa>>bits.mantissa)>1)
47                 ++biased_exponent;
48
49         if(biased_exponent>=exponent_mask || infinity)
50                 // Overflow, return infinity
51                 return UInt64(sign<<bits.exponent | exponent_mask)<<bits.mantissa;
52         else if(biased_exponent<=0 || !mantissa)
53                 // Underflow, return zero
54                 return 0;
55         else
56         {
57                 UInt64 value = rounded_mantissa&mantissa_mask;
58                 value |= UInt64(biased_exponent)<<bits.mantissa;
59                 value |= UInt64(sign)<<(bits.mantissa+bits.exponent);
60                 return value;
61         }
62 }
63
64
65 // exponent = log_2(bits)*3-7
66 BinFloat::Bits::Bits(unsigned bits):
67         exponent(log(bits)*4.3281-7),
68         mantissa(bits-exponent-1)
69 { }
70
71 } // namespace DataFile
72 } // namespace Msp