source: trunk/src/real.cpp @ 971

Last change on this file since 971 was 971, checked in by sam, 11 years ago

core: handle zero, negative zero and infinite in the real constructor,
and add a test suite check for unary minus.

File size: 4.4 KB
Line 
1//
2// Lol Engine
3//
4// Copyright: (c) 2010-2011 Sam Hocevar <sam@hocevar.net>
5//   This program is free software; you can redistribute it and/or
6//   modify it under the terms of the Do What The Fuck You Want To
7//   Public License, Version 2, as published by Sam Hocevar. See
8//   http://sam.zoy.org/projects/COPYING.WTFPL for more details.
9//
10
11#if defined HAVE_CONFIG_H
12#   include "config.h"
13#endif
14
15#include <cstring>
16#include <cstdio>
17
18#include "core.h"
19
20using namespace std;
21
22namespace lol
23{
24
25real::real(float f)
26{
27    union { float f; uint32_t x; } u = { f };
28
29    uint32_t sign = u.x & 0x80000000u;
30    uint32_t exponent = (u.x >> 23) & 0xff;
31
32    switch (exponent)
33    {
34    case 0x00:
35    case 0xff:
36        m_signexp = sign | exponent;
37        break;
38    default:
39        m_signexp = sign | (exponent + (1 << 30) - (1 << 7));
40        break;
41    }
42
43    m_mantissa[0] = u.x >> 7;
44    m_mantissa[1] = u.x << 9;
45    memset(m_mantissa + 2, 0, sizeof(m_mantissa) - sizeof(m_mantissa[0]));
46}
47
48real::operator float() const
49{
50    union { float f; uint32_t x; } u;
51
52    uint32_t sign = m_signexp & 0x80000000u;
53    uint32_t exponent = m_signexp & 0x7fffffffu;
54    uint32_t mantissa = (m_mantissa[0] << 7) | (m_mantissa[1] >> 9);
55
56    int e = (int)(m_signexp & 0x7fffffffu) - (1 << 30) + (1 << 7);
57
58    if (e < 0)
59        u.x = sign;
60    else if (e >= 0xff)
61        u.x = sign | (0xff << 23);
62    else
63        u.x = sign | (e << 23) | mantissa;
64
65    return u.f;
66}
67
68real real::operator -()
69{
70    m_signexp ^= 0x80000000u;
71    return *this;
72}
73
74real real::operator +(real const &x) const
75{
76    if ((m_signexp << 1) < (x.m_signexp << 1))
77        return x + *this;
78
79    if (x.m_signexp << 1 == 0)
80        return *this;
81
82    /* For now, assume both numbers are positive. */
83    real ret;
84
85    int e1 = (m_signexp & 0x7fffffffu) - (1 << 30) + 1;
86    int e2 = (x.m_signexp & 0x7fffffffu) - (1 << 30) + 1;
87
88    int bigoff = (e1 - e2) / (sizeof(uint16_t) * 8);
89    int off = e1 - e2 - bigoff * (sizeof(uint16_t) * 8);
90
91    ret.m_signexp = m_signexp;
92
93    uint32_t carry = 0;
94    for (int i = 0; i < BIGITS; i++)
95    {
96        carry = m_mantissa[BIGITS - 1 - i];
97        if (BIGITS - 1 - i - bigoff >= 0)
98            carry += x.m_mantissa[BIGITS - 1 - i - bigoff] >> off;
99        else if (BIGITS - 1 - i - bigoff == -1)
100            carry += 0x0001u >> off;
101
102        if (BIGITS - 1 - i - bigoff - 1 >= 0)
103            carry += (x.m_mantissa[BIGITS - 1 - i - bigoff - 1] << (16 - off)) & 0xffffu;
104        else if (BIGITS - 1 - i - bigoff - 1 == -1)
105            carry += 0x0001u << (16 - off);
106
107        ret.m_mantissa[BIGITS - 1 - i] = carry;
108        carry >>= 16;
109    }
110
111    /* Renormalise in case we overflowed the mantissa */
112    if (carry)
113    {
114        carry--;
115        for (int i = 0; i < BIGITS; i++)
116        {
117            uint16_t tmp = ret.m_mantissa[i];
118            ret.m_mantissa[i] = (carry << 15) | (tmp >> 1);
119            carry = tmp & 0x0001u;
120        }
121        ret.m_signexp++;
122    }
123
124    return ret;
125}
126
127real real::operator *(real const &x) const
128{
129    real ret;
130
131    ret.m_signexp = (m_signexp ^ x.m_signexp) & 0x80000000u;
132    int e = (m_signexp & 0x7fffffffu) - (1 << 30) + 1
133          + (x.m_signexp & 0x7fffffffu) - (1 << 30) + 1;
134
135    /* Accumulate low order product; no need to store it, we just
136     * want the carry value */
137    uint32_t carry = 0;
138    for (int i = 0; i < BIGITS; i++)
139    {
140        for (int j = 0; j < i + 1; j++)
141            carry += m_mantissa[BIGITS - 1 - j]
142                   * x.m_mantissa[BIGITS - 1 + j - i];
143        carry >>= 16;
144    }
145
146    for (int i = 0; i < BIGITS; i++)
147    {
148        for (int j = i + 1; j < BIGITS; j++)
149            carry += m_mantissa[BIGITS - 1 - j]
150                   * x.m_mantissa[j - 1 - i];
151
152        carry += m_mantissa[BIGITS - 1 - i];
153        carry += x.m_mantissa[BIGITS - 1 - i];
154        ret.m_mantissa[BIGITS - 1 - i] = carry & 0xffffu;
155        carry >>= 16;
156    }
157
158    /* Renormalise in case we overflowed the mantissa */
159    if (carry)
160    {
161        carry--;
162        for (int i = 0; i < BIGITS; i++)
163        {
164            uint16_t tmp = ret.m_mantissa[i];
165            ret.m_mantissa[i] = (carry << 15) | (tmp >> 1);
166            carry = tmp & 0x0001u;
167        }
168        e++;
169    }
170
171    ret.m_signexp |= e + (1 << 30) - 1;
172
173    return ret;
174}
175
176void real::print() const
177{
178    printf("%x  %08x  ", m_signexp >> 31, (m_signexp << 1) >> 1);
179    for (int i = 0; i < BIGITS; i++)
180        printf("%04x ", m_mantissa[i]);
181    printf("\n");
182}
183
184} /* namespace lol */
185
Note: See TracBrowser for help on using the repository browser.