| 73 | } |
| 74 | |
| 75 | void FieldModel<decimal_t>::set(decimal_t value) noexcept |
| 76 | { |
| 77 | assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!"); |
| 78 | if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size()) |
| 79 | return; |
| 80 | |
| 81 | // The most we can scale by is 10^28, which is just slightly more |
| 82 | // than 2^93. So a float with an exponent of -94 could just |
| 83 | // barely reach 0.5, but smaller exponents will always round to zero. |
| 84 | const uint32_t DBLBIAS = 1022; |
| 85 | |
| 86 | // Get exponent value |
| 87 | double dValue = (double)value; |
| 88 | int32_t iExp = (int32_t)(((uint32_t)(extract(dValue) >> 52) & 0x7FFu) - DBLBIAS); |
| 89 | if ((iExp < -94) || (iExp > 96)) |
| 90 | { |
| 91 | // Value too big for .NET Decimal (exponent is limited to [-94, 96]) |
| 92 | memset((uint8_t*)(_buffer.data() + _buffer.offset() + fbe_offset()), 0, 16); |
| 93 | return; |
| 94 | } |
| 95 | |
| 96 | uint32_t flags = 0; |
| 97 | if (dValue < 0) |
| 98 | { |
| 99 | dValue = -dValue; |
| 100 | flags = 0x80000000; |
| 101 | } |
| 102 | |
| 103 | // Round the input to a 15-digit integer. The R8 format has |
| 104 | // only 15 digits of precision, and we want to keep garbage digits |
| 105 | // out of the Decimal were making. |
| 106 | |
| 107 | // Calculate max power of 10 input value could have by multiplying |
| 108 | // the exponent by log10(2). Using scaled integer multiplcation, |
| 109 | // log10(2) * 2 ^ 16 = .30103 * 65536 = 19728.3. |
| 110 | int32_t iPower = 14 - ((iExp * 19728) >> 16); |
| 111 | |
| 112 | // iPower is between -14 and 43 |
| 113 | if (iPower >= 0) |
| 114 | { |
| 115 | // We have less than 15 digits, scale input up. |
| 116 | if (iPower > 28) |
| 117 | iPower = 28; |
| 118 | |
| 119 | dValue *= pow(10.0, iPower); |
| 120 | } |
| 121 | else |
| 122 | { |
| 123 | if ((iPower != -1) || (dValue >= 1E15)) |
| 124 | dValue /= pow(10.0, -iPower); |
| 125 | else |
| 126 | iPower = 0; // didn't scale it |
| 127 | } |
| 128 | |
| 129 | assert(dValue < 1E15); |
| 130 | if ((dValue < 1E14) && (iPower < 28)) |
| 131 | { |
| 132 | dValue *= 10; |