~kunquat-maintainers/kunquat/kunquat-media

« back to all changes in this revision

Viewing changes to src/lib/Real.c

  • Committer: Toni Ruottu
  • Date: 2009-07-06 22:23:01 UTC
  • Revision ID: toni.ruottu@iki.fi-20090706222301-re2ik5yxsojg2qms
removed source code, moved contents of contrib to root directory

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
 
2
 
 
3
 
/*
4
 
 * Copyright 2009 Tomi Jylhä-Ollila
5
 
 *
6
 
 * This file is part of Kunquat.
7
 
 *
8
 
 * Kunquat is free software: you can redistribute it and/or modify
9
 
 * it under the terms of the GNU General Public License as published by
10
 
 * the Free Software Foundation, either version 3 of the License, or
11
 
 * (at your option) any later version.
12
 
 *
13
 
 * Kunquat is distributed in the hope that it will be useful,
14
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 
 * GNU General Public License for more details.
17
 
 *
18
 
 * You should have received a copy of the GNU General Public License
19
 
 * along with Kunquat.  If not, see <http://www.gnu.org/licenses/>.
20
 
 */
21
 
 
22
 
 
23
 
#include <stdlib.h>
24
 
#include <assert.h>
25
 
#include <inttypes.h>
26
 
#include <math.h>
27
 
 
28
 
#include <Real.h>
29
 
 
30
 
 
31
 
/**
32
 
 * Reduces a Real object into lowest terms.
33
 
 *
34
 
 * Does nothing unless the Real object is a fraction.
35
 
 *
36
 
 * \param real   The Real object -- must not be \c NULL.
37
 
 *
38
 
 * \return   The parameter \a real.
39
 
 */
40
 
static Real* Real_normalise(Real* real);
41
 
 
42
 
 
43
 
#ifndef NDEBUG
44
 
    /**
45
 
     * Validates a Real object.
46
 
     *
47
 
     * \param real   The Real object.
48
 
     *
49
 
     * \return   \c true if and only if the Real object is valid.
50
 
     */
51
 
    static bool Real_validate_(Real* real);
52
 
    #define Real_validate(real)   ( assert(Real_validate_(real)) )
53
 
#else
54
 
    #define Real_validate(real)   ((void)0)
55
 
#endif
56
 
 
57
 
 
58
 
/**
59
 
 * Performs integer multiplication with overflow check.
60
 
 *
61
 
 * \param a     The first term.
62
 
 * \param b     The second term.
63
 
 * \param res   Pointer to the result variable -- must not be \c NULL. If an
64
 
 *              overflow would occur, the stored value will not be changed.
65
 
 *
66
 
 * \return   \c true if \a a * \a b was calculated successfully, or \c false
67
 
 *           if the result would become larger than INT64_MAX in magnitude.
68
 
 */
69
 
static bool safe_mul(int64_t a, int64_t b, int64_t* res);
70
 
 
71
 
 
72
 
Real* Real_init(Real* real)
73
 
{
74
 
    assert(real != NULL);
75
 
    return Real_init_as_frac(real, 1, 1);
76
 
}
77
 
 
78
 
 
79
 
Real* Real_init_as_frac(Real* real, int64_t numerator, int64_t denominator)
80
 
{
81
 
    assert(real != NULL);
82
 
    assert(denominator > 0);
83
 
    real->is_frac = 1;
84
 
    real->fod.frac.numerator = numerator;
85
 
    real->fod.frac.denominator = denominator;
86
 
    return Real_normalise(real);
87
 
}
88
 
 
89
 
 
90
 
Real* Real_init_as_double(Real* real, double val)
91
 
{
92
 
    assert(real != NULL);
93
 
    real->is_frac = 0;
94
 
    real->fod.doub = val;
95
 
    return real;
96
 
}
97
 
 
98
 
 
99
 
bool Real_is_frac(Real* real)
100
 
{
101
 
    Real_validate(real);
102
 
    return real->is_frac;
103
 
}
104
 
 
105
 
 
106
 
int64_t Real_get_numerator(Real* real)
107
 
{
108
 
    Real_validate(real);
109
 
    if (!real->is_frac)
110
 
    {
111
 
        return (int64_t)real->fod.doub;
112
 
    }
113
 
    return real->fod.frac.numerator;
114
 
}
115
 
 
116
 
 
117
 
int64_t Real_get_denominator(Real* real)
118
 
{
119
 
    Real_validate(real);
120
 
    if (!real->is_frac)
121
 
    {
122
 
        return 1;
123
 
    }
124
 
    return real->fod.frac.denominator;
125
 
}
126
 
 
127
 
 
128
 
double Real_get_double(Real* real)
129
 
{
130
 
    Real_validate(real);
131
 
    if (real->is_frac)
132
 
    {
133
 
        return (double)real->fod.frac.numerator
134
 
                / (double)real->fod.frac.denominator;
135
 
    }
136
 
    return real->fod.doub;
137
 
}
138
 
 
139
 
 
140
 
Real* Real_copy(Real* dest, Real* src)
141
 
{
142
 
    assert(dest != NULL);
143
 
    Real_validate(src);
144
 
    if (src->is_frac)
145
 
    {
146
 
        dest->is_frac = 1;
147
 
        dest->fod.frac.numerator = src->fod.frac.numerator;
148
 
        dest->fod.frac.denominator = src->fod.frac.denominator;
149
 
        Real_validate(dest);
150
 
        return dest;
151
 
    }
152
 
    dest->is_frac = 0;
153
 
    dest->fod.doub = src->fod.doub;
154
 
    Real_validate(dest);
155
 
    return dest;
156
 
}
157
 
 
158
 
 
159
 
Real* Real_mul(Real* ret, Real* real1, Real* real2)
160
 
{
161
 
    assert(ret != NULL);
162
 
    Real_validate(real1);
163
 
    Real_validate(real2);
164
 
    if (real1->is_frac && real2->is_frac)
165
 
    {
166
 
        int64_t num = 0;
167
 
        int64_t den = 0;
168
 
        if (safe_mul(real1->fod.frac.numerator,
169
 
                    real2->fod.frac.numerator, &num)
170
 
                && safe_mul(real1->fod.frac.denominator,
171
 
                    real2->fod.frac.denominator, &den))
172
 
        {
173
 
            ret->is_frac = 1;
174
 
            ret->fod.frac.numerator = num;
175
 
            ret->fod.frac.denominator = den;
176
 
            return Real_normalise(ret);
177
 
        }
178
 
    }
179
 
    return Real_init_as_double(ret, Real_get_double(real1) * Real_get_double(real2));
180
 
}
181
 
 
182
 
 
183
 
Real* Real_div(Real* ret, Real* dividend, Real* divisor)
184
 
{
185
 
    assert(ret != NULL);
186
 
    Real_validate(dividend);
187
 
    Real_validate(divisor);
188
 
    if (dividend->is_frac && divisor->is_frac)
189
 
    {
190
 
        assert(divisor->fod.frac.numerator != 0);
191
 
        int64_t num = 0;
192
 
        int64_t den = 0;
193
 
        if (safe_mul(dividend->fod.frac.numerator,
194
 
                    divisor->fod.frac.denominator, &num)
195
 
                && safe_mul(dividend->fod.frac.denominator,
196
 
                    divisor->fod.frac.numerator, &den))
197
 
        {
198
 
            if (den < 0)
199
 
            {
200
 
                num = -num;
201
 
                den = -den;
202
 
            }
203
 
            ret->is_frac = 1;
204
 
            ret->fod.frac.numerator = num;
205
 
            ret->fod.frac.denominator = den;
206
 
            return Real_normalise(ret);
207
 
        }
208
 
    }
209
 
    assert(Real_get_double(divisor) != 0);
210
 
    return Real_init_as_double(ret, Real_get_double(dividend) / Real_get_double(divisor));
211
 
}
212
 
 
213
 
 
214
 
double Real_mul_float(Real* real, double d)
215
 
{
216
 
    Real_validate(real);
217
 
    return Real_get_double(real) * d;
218
 
}
219
 
 
220
 
 
221
 
int Real_cmp(Real* real1, Real* real2)
222
 
{
223
 
    Real_validate(real1);
224
 
    Real_validate(real2);
225
 
    if (real1->is_frac && real2->is_frac)
226
 
    {
227
 
        int64_t num1 = real1->fod.frac.numerator;
228
 
        int64_t den1 = real1->fod.frac.denominator;
229
 
        int64_t num2 = real2->fod.frac.numerator;
230
 
        int64_t den2 = real2->fod.frac.denominator;
231
 
        if (num1 == num2 && den1 == den2)
232
 
        {
233
 
            return 0;
234
 
        }
235
 
        int64_t term1 = 0;
236
 
        int64_t term2 = 0;
237
 
        if (safe_mul(num1, den2, &term1)
238
 
                && safe_mul(num2, den1, &term2))
239
 
        {
240
 
            if (term1 < term2)
241
 
                return -1;
242
 
            else if (term1 > term2)
243
 
                return 1;
244
 
            return 0;
245
 
        }
246
 
    }
247
 
    double val1 = Real_get_double(real1);
248
 
    double val2 = Real_get_double(real2);
249
 
    if (val1 < val2)
250
 
    {
251
 
        return -1;
252
 
    }
253
 
    else if (val1 > val2)
254
 
    {
255
 
        return 1;
256
 
    }
257
 
    return 0;
258
 
}
259
 
 
260
 
 
261
 
Real* Real_normalise(Real* real)
262
 
{
263
 
    Real_validate(real);
264
 
    if (!real->is_frac)
265
 
    {
266
 
        return real;
267
 
    }
268
 
    if (real->fod.frac.numerator == INT64_MIN)
269
 
    {
270
 
        // get rid of INT64_MIN for imaxabs()
271
 
        if ((INT64_MIN % 2) == -1)
272
 
        {
273
 
            // Potentially suboptimal: real may not be in lowest terms here
274
 
            // if INT_LEAST64_MIN is used.
275
 
            return real;
276
 
        }
277
 
        if ((real->fod.frac.denominator & 1) == 0)
278
 
        {
279
 
            real->fod.frac.numerator = INT64_MIN / 2;
280
 
            real->fod.frac.denominator >>= 1;
281
 
        }
282
 
        else
283
 
        {
284
 
            // INT64_MIN is has the form -2^n,
285
 
            // so the fraction is irreducible here.
286
 
            // Potentially suboptimal if INT_LEAST64_MIN is used.
287
 
            return real;
288
 
        }
289
 
    }
290
 
    int k = 0;
291
 
    int64_t num = imaxabs(real->fod.frac.numerator);
292
 
    int64_t den = real->fod.frac.denominator;
293
 
    if (num == 0)
294
 
    {
295
 
        real->fod.frac.denominator = 1;
296
 
        return real;
297
 
    }
298
 
    while ((num & 1) == 0 && (den & 1) == 0)
299
 
    {
300
 
        num >>= 1;
301
 
        den >>= 1;
302
 
        ++k;
303
 
    }
304
 
    do
305
 
    {
306
 
        if ((den & 1) == 0)
307
 
            den >>= 1;
308
 
        else if ((num & 1) == 0)
309
 
            num >>= 1;
310
 
        else if (den >= num)
311
 
            den = (den - num) >> 1;
312
 
        else
313
 
            num = (num - den) >> 1;
314
 
    } while (den > 0);
315
 
    assert(num > 0);
316
 
    num <<= k;
317
 
    real->fod.frac.numerator /= num;
318
 
    real->fod.frac.denominator /= num;
319
 
    Real_validate(real);
320
 
    return real;
321
 
}
322
 
 
323
 
 
324
 
#ifndef NDEBUG
325
 
bool Real_validate_(Real* real)
326
 
{
327
 
    if (real == NULL)
328
 
    {
329
 
        return false;
330
 
    }
331
 
    if (real->is_frac)
332
 
    {
333
 
        if (real->fod.frac.denominator <= 0)
334
 
        {
335
 
            return false;
336
 
        }
337
 
    }
338
 
    else
339
 
    {
340
 
        if (isnan(real->fod.doub))
341
 
        {
342
 
            return false;
343
 
        }
344
 
    }
345
 
    return true;
346
 
}
347
 
#endif
348
 
 
349
 
 
350
 
// Works the way described in http://www.fefe.de/intof.html
351
 
static bool safe_mul(int64_t a, int64_t b, int64_t* res)
352
 
{
353
 
    assert(res != NULL);
354
 
    bool negative = false;
355
 
    if ((a == INT64_MIN || b == INT64_MIN)
356
 
            && a != 0 && b != 0
357
 
            && INT64_MIN < -INT64_MAX)
358
 
    {
359
 
        return false;
360
 
    }
361
 
    if (a < 0)
362
 
    {
363
 
        a = -a;
364
 
        negative = !negative;
365
 
    }
366
 
    if (b < 0)
367
 
    {
368
 
        b = -b;
369
 
        negative = !negative;
370
 
    }
371
 
    uint64_t ahi = (uint64_t)a >> 32;
372
 
    uint64_t bhi = (uint64_t)b >> 32;
373
 
    if (ahi != 0 && bhi != 0)
374
 
    {
375
 
        return false;
376
 
    }
377
 
    uint64_t alo = a & 0xffffffffULL;
378
 
    uint64_t blo = b & 0xffffffffULL;
379
 
    uint64_t hi = (ahi * blo) + (alo * bhi);
380
 
    if (hi > 0x7fffffffULL)
381
 
    {
382
 
        return false;
383
 
    }
384
 
    hi <<= 32;
385
 
    uint64_t lo = alo * blo;
386
 
    if (UINT64_MAX - lo < hi || INT64_MAX < hi + lo)
387
 
    {
388
 
        return false;
389
 
    }
390
 
    *res = hi + lo;
391
 
    if (negative)
392
 
    {
393
 
        *res = -*res;
394
 
    }
395
 
    return true;
396
 
}
397
 
 
398