source: trunk/src/real.cpp @ 970

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

core: start working on the extended floating point addition.

File size: 4.0 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    int e = ((u.x >> 23) & 0xff) + (1 << 30) - (1 << 7);
31
32    m_signexp = sign | e;
33    m_mantissa[0] = u.x >> 7;
34    m_mantissa[1] = u.x << 9;
35    memset(m_mantissa + 2, 0, sizeof(m_mantissa) - sizeof(m_mantissa[0]));
36}
37
38real::operator float() const
39{
40    union { float f; uint32_t x; } u;
41
42    u.x = m_mantissa[0] << 7;
43    u.x |= m_mantissa[1] >> 9;
44    u.x |= ((m_signexp & 0x7fffffffu) - (1 << 30) + (1 << 7)) << 23;
45    u.x |= m_signexp & 0x80000000u;
46
47    return u.f;
48}
49
50real real::operator -()
51{
52    m_signexp ^= 0x80000000u;
53    return *this;
54}
55
56real real::operator +(real const &x) const
57{
58    if ((m_signexp << 1) < (x.m_signexp << 1))
59        return x + *this;
60
61    /* For now, assume both numbers are positive. */
62    real ret;
63
64    int e1 = (m_signexp & 0x7fffffffu) - (1 << 30) + 1;
65    int e2 = (x.m_signexp & 0x7fffffffu) - (1 << 30) + 1;
66
67    int bigoff = (e1 - e2) / (sizeof(uint16_t) * 8);
68    int off = e1 - e2 - bigoff * (sizeof(uint16_t) * 8);
69
70    ret.m_signexp = m_signexp;
71
72    uint32_t carry = 0;
73    for (int i = 0; i < BIGITS; i++)
74    {
75        carry = m_mantissa[BIGITS - 1 - i];
76        if (BIGITS - 1 - i - bigoff >= 0)
77            carry += x.m_mantissa[BIGITS - 1 - i - bigoff] >> off;
78        else if (BIGITS - 1 - i - bigoff == -1)
79            carry += 0x0001u >> off;
80
81        if (BIGITS - 1 - i - bigoff - 1 >= 0)
82            carry += (x.m_mantissa[BIGITS - 1 - i - bigoff - 1] << (16 - off)) & 0xffffu;
83        else if (BIGITS - 1 - i - bigoff - 1 == -1)
84            carry += 0x0001u << (16 - off);
85
86        ret.m_mantissa[BIGITS - 1 - i] = carry;
87        carry >>= 16;
88    }
89
90    /* Renormalise in case we overflowed the mantissa */
91    if (carry)
92    {
93        carry--;
94        for (int i = 0; i < BIGITS; i++)
95        {
96            uint16_t tmp = ret.m_mantissa[i];
97            ret.m_mantissa[i] = (carry << 15) | (tmp >> 1);
98            carry = tmp & 0x0001u;
99        }
100        ret.m_signexp++;
101    }
102
103    return ret;
104}
105
106real real::operator *(real const &x) const
107{
108    real ret;
109
110    ret.m_signexp = (m_signexp ^ x.m_signexp) & 0x80000000u;
111    int e = (m_signexp & 0x7fffffffu) - (1 << 30) + 1
112          + (x.m_signexp & 0x7fffffffu) - (1 << 30) + 1;
113
114    /* Accumulate low order product; no need to store it, we just
115     * want the carry value */
116    uint32_t carry = 0;
117    for (int i = 0; i < BIGITS; i++)
118    {
119        for (int j = 0; j < i + 1; j++)
120            carry += m_mantissa[BIGITS - 1 - j]
121                   * x.m_mantissa[BIGITS - 1 + j - i];
122        carry >>= 16;
123    }
124
125    for (int i = 0; i < BIGITS; i++)
126    {
127        for (int j = i + 1; j < BIGITS; j++)
128            carry += m_mantissa[BIGITS - 1 - j]
129                   * x.m_mantissa[j - 1 - i];
130
131        carry += m_mantissa[BIGITS - 1 - i];
132        carry += x.m_mantissa[BIGITS - 1 - i];
133        ret.m_mantissa[BIGITS - 1 - i] = carry & 0xffffu;
134        carry >>= 16;
135    }
136
137    /* Renormalise in case we overflowed the mantissa */
138    if (carry)
139    {
140        carry--;
141        for (int i = 0; i < BIGITS; i++)
142        {
143            uint16_t tmp = ret.m_mantissa[i];
144            ret.m_mantissa[i] = (carry << 15) | (tmp >> 1);
145            carry = tmp & 0x0001u;
146        }
147        e++;
148    }
149
150    ret.m_signexp |= e + (1 << 30) - 1;
151
152    return ret;
153}
154
155void real::print() const
156{
157    printf("%x  %08x  ", m_signexp >> 31, (m_signexp << 1) >> 1);
158    for (int i = 0; i < BIGITS; i++)
159        printf("%04x ", m_mantissa[i]);
160    printf("\n");
161}
162
163} /* namespace lol */
164
Note: See TracBrowser for help on using the repository browser.