1 /*
2 This code is based on code from the Geometric Tools library,
3 which is licensed under a boost license.
4 Such usage is permitted by the boost license; for details,
5 please see the boost license below.
6 */
7
8 // Geometric Tools, LLC
9 // Copyright (c) 1998-2014
10 // Distributed under the Boost Software License, Version 1.0.
11 // http://www.boost.org/LICENSE_1_0.txt
12 // http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
13
14 /*************************************************************************
15 * *
16 * We release our improvements to the wildMagic code under our standard *
17 * Vega FEM license, as follows: *
18 * *
19 * Vega FEM Simulation Library Version 3.1 *
20 * *
21 * "improvements to the wildMagic library" , Copyright (C) 2016 USC *
22 * All rights reserved. *
23 * *
24 * Code author: Yijing Li *
25 * http://www.jernejbarbic.com/code *
26 * *
27 * Funding: National Science Foundation *
28 * *
29 * This library is free software; you can redistribute it and/or *
30 * modify it under the terms of the BSD-style license that is *
31 * included with this library in the file LICENSE.txt *
32 * *
33 * This library is distributed in the hope that it will be useful, *
34 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
35 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the file *
36 * LICENSE.TXT for more details. *
37 * *
38 *************************************************************************/
39
40
41 #ifndef RATIONAL_H
42 #define RATIONAL_H
43
44
45 #include "integer.h"
46 #include <stdint.h>
47
48 class RationalException : public std::exception
49 {
50 public:
51 RationalException(const char * reason);
52 RationalException(const std::string & reason);
53 virtual ~RationalException() throw();
54 virtual const char * what() const throw();
55
56 protected:
57 std::string r;
58 };
59
60 // N is the number of 32-bit words per Integer numerator/denominator
61 template <int N>
62 class Rational
63 {
64 public:
65
66 // Construction.
67 Rational (); // default rational is 0/1
68 Rational (const Rational & rat);
69 Rational (const Integer<N> & numer);
70 Rational (const Integer<N> & numer, const Integer<N>& denom);
71
72 // Construction converters.
73 Rational (int numer);
74 Rational (int numer, int denom);
75 Rational (float value);
76 Rational (double value);
77
78 // Member access.
Numer()79 inline Integer<N> & Numer () { return mNumer; }
Denom()80 inline Integer<N> & Denom () { return mDenom; }
Numer()81 inline const Integer<N> & Numer () const { return mNumer; }
Denom()82 inline const Integer<N> & Denom () const { return mDenom; }
83
84 // Assignment.
85 Rational & operator= (const Rational & rat);
86
87 // Comparison.
88 bool operator== (const Rational & rat) const;
89 bool operator!= (const Rational & rat) const;
90 bool operator<= (const Rational & rat) const;
91 bool operator< (const Rational & rat) const;
92 bool operator>= (const Rational & rat) const;
93 bool operator> (const Rational & rat) const;
94
95 // Arithmetic operations.
96 Rational operator+ (const Rational & rat) const;
97 Rational operator- (const Rational & rat) const;
98 Rational operator* (const Rational & rat) const;
99 Rational operator/ (const Rational & rat) const;
100 Rational operator- () const;
101
102 // Arithmetic updates.
103 Rational & operator+= (const Rational & rat);
104 Rational & operator-= (const Rational & rat);
105 Rational & operator*= (const Rational & rat);
106 Rational & operator/= (const Rational & rat);
107
108 // Conversions to float and double.
109 void convertTo (float& value) const;
110 void convertTo (double& value) const;
111 double toDouble() const;
112
113 // Compute the absolute value of the rational number.
114 Rational abs () const;
115
116 private:
117 typedef RationalException Exception;
118 // Cancel any powers of two common to the numerator and
119 // denominator.
120 void EliminatePowersOfTwo ();
121
122 Integer<N> mNumer, mDenom;
123 };
124
125 template <int N>
126 Rational<N> operator+ (const Integer<N>& ival, const Rational<N>& rat);
127
128 template <int N>
129 Rational<N> operator- (const Integer<N>& ival, const Rational<N>& rat);
130
131 template <int N>
132 Rational<N> operator* (const Integer<N>& ival, const Rational<N>& rat);
133
134 template <int N>
135 Rational<N> operator/ (const Integer<N>& ival, const Rational<N>& rat);
136
137
138
Rational()139 template <int N> Rational<N>::Rational () : mNumer(0), mDenom(1) {}
140
Rational(const Rational & rat)141 template <int N> Rational<N>::Rational (const Rational & rat) : mNumer(rat.mNumer), mDenom(rat.mDenom) {}
142
Rational(const Integer<N> & numer)143 template <int N> Rational<N>::Rational (const Integer<N>& numer) : mNumer(numer), mDenom(1) {}
144
Rational(const Integer<N> & numer,const Integer<N> & denom)145 template <int N> Rational<N>::Rational (const Integer<N>& numer, const Integer<N>& denom) : mNumer(numer), mDenom(denom) {}
146
Rational(int numer)147 template <int N> Rational<N>::Rational (int numer) : mNumer(numer), mDenom(1) {}
148
Rational(int numer,int denom)149 template <int N> Rational<N>::Rational (int numer, int denom) : mNumer(numer), mDenom(denom) {}
150
151 template <int N> Rational<N>& Rational<N>::operator= (const Rational & rat)
152 {
153 if (this != &rat)
154 {
155 mNumer = rat.mNumer;
156 mDenom = rat.mDenom;
157 }
158 return *this;
159 }
160
161 template <int N> bool Rational<N>::operator== (const Rational & rat) const
162 {
163 return mNumer*rat.mDenom == mDenom*rat.mNumer;
164 }
165
166 template <int N> bool Rational<N>::operator!= (const Rational & rat) const
167 {
168 return mNumer*rat.mDenom != mDenom*rat.mNumer;
169 }
170
171 template <int N> bool Rational<N>::operator<= (const Rational & rat) const
172 {
173 Integer<N> prod0 = mNumer*rat.mDenom;
174 Integer<N> prod1 = mDenom*rat.mNumer;
175 if (mDenom > 0)
176 return (rat.mDenom > 0 ? prod0 <= prod1 : prod0 >= prod1);
177 else
178 return (rat.mDenom > 0 ? prod0 >= prod1 : prod0 <= prod1);
179 }
180
181 template <int N> bool Rational<N>::operator< (const Rational & rat) const
182 {
183 Integer<N> prod0 = mNumer*rat.mDenom;
184 Integer<N> prod1 = mDenom*rat.mNumer;
185 if (mDenom > 0)
186 return (rat.mDenom > 0 ? prod0 < prod1 : prod0 > prod1);
187 else
188 return (rat.mDenom > 0 ? prod0 > prod1 : prod0 < prod1);
189 }
190
191 template <int N> bool Rational<N>::operator>= (const Rational & rat) const
192 {
193 Integer<N> prod0 = mNumer*rat.mDenom;
194 Integer<N> prod1 = mDenom*rat.mNumer;
195 if (mDenom > 0)
196 return (rat.mDenom > 0 ? prod0 >= prod1 : prod0 <= prod1);
197 else
198 return (rat.mDenom > 0 ? prod0 <= prod1 : prod0 >= prod1);
199 }
200
201 template <int N> bool Rational<N>::operator> (const Rational & rat) const
202 {
203 Integer<N> prod0 = mNumer*rat.mDenom;
204 Integer<N> prod1 = mDenom*rat.mNumer;
205 if (mDenom > 0)
206 return (rat.mDenom > 0 ? prod0 > prod1 : prod0 < prod1);
207 else
208 return (rat.mDenom > 0 ? prod0 < prod1 : prod0 > prod1);
209 }
210
211 template <int N> Rational<N> Rational<N>::operator+ (const Rational & rat) const
212 {
213 Rational sum;
214 sum.mNumer = mNumer*rat.mDenom + mDenom*rat.mNumer;
215 sum.mDenom = mDenom*rat.mDenom;
216 sum.EliminatePowersOfTwo();
217 return sum;
218 }
219
220 template <int N> Rational<N> Rational<N>::operator- (const Rational & rat) const
221 {
222 Rational diff;
223 diff.mNumer = mNumer*rat.mDenom - mDenom*rat.mNumer;
224 diff.mDenom = mDenom*rat.mDenom;
225 diff.EliminatePowersOfTwo();
226 return diff;
227 }
228
229 template <int N> Rational<N> Rational<N>::operator* (const Rational & rat) const
230 {
231 Rational prod;
232 prod.mNumer = mNumer*rat.mNumer;
233 prod.mDenom = mDenom*rat.mDenom;
234 prod.EliminatePowersOfTwo();
235 return prod;
236 }
237
238 template <int N> Rational<N> Rational<N>::operator/ (const Rational & rat) const
239 {
240 Rational quot;
241 quot.mNumer = mNumer*rat.mDenom;
242 quot.mDenom = mDenom*rat.mNumer;
243 quot.EliminatePowersOfTwo();
244 return quot;
245 }
246
247 template <int N> Rational<N> Rational<N>::operator- () const
248 {
249 Rational neg;
250 neg.mNumer = -mNumer;
251 neg.mDenom = mDenom;
252 return neg;
253 }
254
255 template <int N> Rational<N> operator+ (const Integer<N>& ival, const Rational<N>& rat)
256 {
257 Rational<N> sum;
258 sum.Numer() = ival*rat.Denom() + rat.Numer();
259 sum.Denom() = rat.Denom();
260 return sum;
261 }
262
263 template <int N> Rational<N> operator- (const Integer<N>& ival, const Rational<N>& rat)
264 {
265 Rational<N> diff;
266 diff.Numer() = ival*rat.Denom() - rat.Numer();
267 diff.Denom() = rat.Denom();
268 return diff;
269 }
270 //----------------------------------------------------------------------------
271 template <int N>
272 Rational<N> operator* (const Integer<N>& ival, const Rational<N>& rat)
273 {
274 Rational<N> prod;
275 prod.Numer() = ival*rat.Numer();
276 prod.Denom() = rat.Denom();
277 return prod;
278 }
279 //----------------------------------------------------------------------------
280 template <int N>
281 Rational<N> operator/ (const Integer<N>& ival, const Rational<N>& rat)
282 {
283 Rational<N> quot;
284 quot.Numer() = rat.Denom()*ival;
285 quot.Denom() = rat.Numer();
286 return quot;
287 }
288 //----------------------------------------------------------------------------
289 template <int N>
290 Rational<N>& Rational<N>::operator+= (const Rational & rat)
291 {
292 *this = *this + rat;
293 EliminatePowersOfTwo();
294 return *this;
295 }
296 //----------------------------------------------------------------------------
297 template <int N>
298 Rational<N>& Rational<N>::operator-= (const Rational & rat)
299 {
300 *this = *this - rat;
301 EliminatePowersOfTwo();
302 return *this;
303 }
304 //----------------------------------------------------------------------------
305 template <int N>
306 Rational<N>& Rational<N>::operator*= (const Rational & rat)
307 {
308 *this = (*this)*rat;
309 EliminatePowersOfTwo();
310 return *this;
311 }
312 //----------------------------------------------------------------------------
313 template <int N>
314 Rational<N>& Rational<N>::operator/= (const Rational & rat)
315 {
316 *this = (*this)/rat;
317 EliminatePowersOfTwo();
318 return *this;
319 }
320 //----------------------------------------------------------------------------
321 template <int N>
abs()322 Rational<N> Rational<N>::abs () const
323 {
324 return (*this >= 0 ? *this : -(*this));
325 }
326 //----------------------------------------------------------------------------
327 template <int N>
EliminatePowersOfTwo()328 void Rational<N>::EliminatePowersOfTwo ()
329 {
330 if ((mNumer.buffer[0] & 1) > 0
331 || (mDenom.buffer[0] & 1) > 0)
332 {
333 // Neither term is divisible by 2 (quick out).
334 return;
335 }
336
337 int block0 = mNumer.getTrailingBlock();
338 if (block0 == -1)
339 {
340 // Numerator is zero.
341 mDenom = 1;
342 return;
343 }
344
345 int block1 = mDenom.getTrailingBlock();
346 if (block1 < 0)
347 throw Exception("Denominator should never be zero in Rational<N>::EliminatePowersOfTwo");
348
349 int minBlock = (block0 < block1 ? block0 : block1);
350 int bit0 = mNumer.getTrailingBit(block0);
351 int bit1 = mDenom.getTrailingBit(block1);
352 int minBit = (bit0 < bit1 ? bit0 : bit1);
353 int shift = 16*minBlock + minBit;
354 mNumer >>= shift;
355 mDenom >>= shift;
356 }
357 //----------------------------------------------------------------------------
358
359 //----------------------------------------------------------------------------
360 // Conversions between rational numbers and 'float'.
361 //----------------------------------------------------------------------------
362 template <int N>
Rational(float value)363 Rational<N>::Rational (float value)
364 {
365 mDenom = Integer<N>(1);
366 if (value == 0.0f)
367 {
368 // Exponent is zero, mantissa is zero, number is +0 (sign bit = 0)
369 // or -0 (sign bit = 1). Return rational value for +0.
370 mNumer = Integer<N>(0);
371 return;
372 }
373
374 unsigned int bits = *(unsigned int*)&value;
375 unsigned int sign = (0x80000000 & bits);
376 int exponent = ((0x7F800000 & bits) >> 23);
377 int mantissa = (0x007FFFFF & bits);
378
379 if (1 <= exponent && exponent <= 254)
380 {
381 // The number is normal: (-1)^s * 2^{e-127} * 1.m
382 mNumer = Integer<N>((1 << 23) + mantissa);
383 int power = exponent - 150;
384 if (power > 0)
385 {
386 mNumer <<= power;
387 }
388 else if (power < 0)
389 {
390 mDenom <<= -power;
391 }
392 }
393 else if (exponent == 0)
394 {
395 // The number is subnormal (denormal): (-1)^s * 2^{-126} * 0.m
396 mNumer = Integer<N>(mantissa);
397 mDenom <<= 149;
398 }
399 else // exponent == 255
400 {
401 #ifdef WM5_ASSERT_ON_RATIONAL_CONVERT_NAN
402 if (mantissa > 0)
403 {
404 if (mantissa & 0x00400000)
405 {
406 assertion(false, "Input is quiet NaN.\n");
407 }
408 else
409 {
410 // Payload is (mantissa & 0x003FFFFF).
411 assertion(false, "Input is signaling NaN.\n");
412 }
413 }
414 else
415 {
416 assertion(false, "Input is an infinity.\n");
417 }
418 #endif
419 // The number is infinite, a quiet NaN, or a signaling NaN. In all
420 // cases, represent them as max_normal_float.
421 mNumer = Integer<N>((1 << 24) - 1);
422 mNumer <<= 104;
423 }
424
425 if (sign)
426 {
427 mNumer = -mNumer;
428 }
429 }
430 //----------------------------------------------------------------------------
431 template <int N>
convertTo(float & value)432 void Rational<N>::convertTo (float& value) const
433 {
434 if (mNumer == 0)
435 {
436 value = 0.0f;
437 return;
438 }
439
440 // Compute the sign of the result and the absolute values of the numerator
441 // and denominator.
442 int sign0 = mNumer.getSign();
443 int sign1 = mDenom.getSign();
444 int sign = sign0*sign1;
445 Integer<N> absNumer = sign0*mNumer;
446 Integer<N> absDenom = sign1*mDenom;
447
448 // Get the leading bits of of the numerator and denominator.
449 int nbit = absNumer.getLeadingBit();
450 int dbit = absDenom.getLeadingBit();
451
452 // The rational is for the form N/D = 2^{nbit-dbit}*(1+n)/(1+d), where
453 // n and d are in [0,1). Convert to N'/D' = (1+n)/(1+d).
454 int power = nbit - dbit;
455 if (power > 0)
456 {
457 absDenom <<= power;
458 }
459 else if (power < 0)
460 {
461 absNumer <<= -power;
462 }
463
464 // To represent (1+n)/(1+d) = 1+m, where m in [0,1), we need n >= d. If
465 // n < d, convert to N"/D" = (2*(1+n))/(1+d) = 1+m, which is in [0,1).
466 if (absNumer < absDenom)
467 {
468 absNumer <<= 1;
469 --power;
470 }
471
472 int result;
473 if (power <= 127)
474 {
475 if (power >= -149)
476 {
477 int exponent, bit, shift;
478 if (power >= -126)
479 {
480 // normal_float, 1.c * 2^{e - 127}
481 exponent = power + 127;
482 bit = 1;
483 shift = 0;
484 }
485 else
486 {
487 // subnormal_float, 0.c * 2^{-126}
488 exponent = 0;
489 bit = 0;
490 absDenom <<= 1;
491 shift = -(power + 127);
492 }
493
494 int mantissa = 0;
495 Integer<N> one(1);
496 for(int mask = ((1 << 22) >> shift); mask > 0; mask >>= 1)
497 {
498 if (bit == 1)
499 {
500 absNumer -= absDenom;
501 }
502 absNumer <<= 1;
503
504 if (absNumer >= absDenom)
505 {
506 bit = 1;
507 mantissa |= mask;
508 }
509 else
510 {
511 bit = 0;
512 }
513 }
514
515 result = (exponent << 23) | mantissa;
516 }
517 else
518 {
519 // Smaller than min_subnormal_float, truncate to zero.
520 result = 0;
521 }
522 }
523 else
524 {
525 // Larger than max_normal_float, truncate to this value.
526 result = 0x7F7FFFFF;
527 }
528
529 if (sign < 0)
530 {
531 result |= 0x80000000;
532 }
533 value = *(float*)&result;
534 }
535 //----------------------------------------------------------------------------
536
537 //----------------------------------------------------------------------------
538 // Conversions between rational numbers and 'double'.
539 //----------------------------------------------------------------------------
540 template <int N>
Rational(double value)541 Rational<N>::Rational (double value)
542 {
543 mDenom = Integer<N>(1);
544 if (value == 0.0)
545 {
546 // Exponent is zero, mantissa is zero, number is +0 (sign bit = 0)
547 // or -0 (sign bit = 1). Return rational value for +0.
548 mNumer = Integer<N>(0);
549 return;
550 }
551
552 uint64_t bits = *(uint64_t*)&value;
553 uint64_t sign = (0x8000000000000000ULL & bits);
554 int exponent = (int)((0x7FFF000000000000LL & bits) >> 52);
555 int64_t mantissa = (0x000FFFFFFFFFFFFFLL & bits);
556 int mlo24 = (int)(mantissa & 0x0000000000FFFFFFLL);
557 int mhi28 = (int)((mantissa & 0x000FFFFFFF000000LL) >> 24);
558
559 if (1 <= exponent && exponent <= 2046)
560 {
561 // The number is normal: (-1)^s * 2^{e-1023} * 1.m
562 Integer<N> numer0(1);
563 numer0 <<= 52; // = (1 << 52);
564 Integer<N> numer1(mhi28);
565 numer1 <<= 24;
566 numer1 += Integer<N>(mlo24);
567 mNumer = numer0 + numer1; // (1LL < 52) + mantissa
568 int power = exponent - 1075;
569 if (power > 0)
570 {
571 mNumer <<= power;
572 }
573 else if (power < 0)
574 {
575 mDenom <<= -power;
576 }
577 }
578 else if (exponent == 0)
579 {
580 // The number is subnormal (denormal): (-1)^s * 2^{-1022} * 0.m
581 mNumer = Integer<N>(mhi28);
582 mNumer <<= 24;
583 mNumer += Integer<N>(mlo24); // mantissa
584 mDenom <<= 1074;
585 }
586 else // exponent == 1023
587 {
588 #ifdef WM5_ASSERT_ON_RATIONAL_CONVERT_NAN
589 if (mantissa > 0)
590 {
591 if (mantissa & 0x0008000000000000LL)
592 {
593 assertion(false, "Input is quiet NaN.\n");
594 }
595 else
596 {
597 // Payload is (mantissa & 0x0007FFFFFFFFFFFFLL).
598 assertion(false, "Input is signaling NaN.\n");
599 }
600 }
601 else
602 {
603 assertion(false, "Input is an infinity.\n");
604 }
605 #endif
606 // The number is infinite, a quiet NaN, or a signaling NaN. In all
607 // cases, represent them as max_normal_double.
608 mNumer = Integer<N>(1);
609 mNumer <<= 53;
610 mNumer -= Integer<N>(1); // (1LL << 53) - 1L
611 mNumer <<= 971;
612 }
613
614 if (sign)
615 {
616 mNumer = -mNumer;
617 }
618 }
619 //----------------------------------------------------------------------------
620 template <int N>
convertTo(double & value)621 void Rational<N>::convertTo (double& value) const
622 {
623 if (mNumer == 0)
624 {
625 value = 0.0;
626 return;
627 }
628
629 // Compute the sign of the result and the absolute values of the numerator
630 // and denominator.
631 int sign0 = mNumer.getSign();
632 int sign1 = mDenom.getSign();
633 int sign = sign0*sign1;
634 Integer<N> absNumer = sign0*mNumer;
635 Integer<N> absDenom = sign1*mDenom;
636
637 // Get the leading bits of of the numerator and denominator.
638 int nbit = absNumer.getLeadingBit();
639 int dbit = absDenom.getLeadingBit();
640
641 // The rational is for the form N/D = 2^{nbit-dbit}*(1+n)/(1+d), where
642 // n and d are in [0,1). Convert to N'/D' = (1+n)/(1+d).
643 int power = nbit - dbit;
644 if (power > 0)
645 {
646 absDenom <<= power;
647 }
648 else if (power < 0)
649 {
650 absNumer <<= -power;
651 }
652
653 // To represent (1+n)/(1+d) = 1+m, where m in [0,1), we need n >= d. If
654 // n < d, convert to N"/D" = (2*(1+n))/(1+d) = 1+m, which is in [0,1).
655 if (absNumer < absDenom)
656 {
657 absNumer <<= 1;
658 --power;
659 }
660
661 int64_t result;
662 if (power <= 1023)
663 {
664 if (power >= -1074)
665 {
666 int64_t exponent;
667 int bit, shift;
668 if (power >= -1022)
669 {
670 // normal_float, 1.c * 2^{e - 1023}
671 exponent = power + 1023;
672 bit = 1;
673 shift = 0;
674 }
675 else
676 {
677 // subnormal_float, 0.c * 2^{-1022}
678 exponent = 0;
679 bit = 0;
680 absDenom <<= 1;
681 shift = -(power + 1023);
682 }
683
684 int64_t mantissa = 0;
685 Integer<N> one(1);
686 for(int64_t mask = ((1LL << 51) >> shift); mask > 0; mask >>= 1)
687 {
688 if (bit == 1)
689 {
690 absNumer -= absDenom;
691 }
692 absNumer <<= 1;
693
694 if (absNumer >= absDenom)
695 {
696 bit = 1;
697 mantissa |= mask;
698 }
699 else
700 {
701 bit = 0;
702 }
703 }
704
705 result = (exponent << 52) | mantissa;
706 }
707 else
708 {
709 // Smaller than min_subnormal_float, truncate to zero.
710 result = 0LL;
711 }
712 }
713 else
714 {
715 // Larger than max_normal_float, truncate to this value.
716 result = 0x7FEFFFFFFFFFFFFFLL;
717 }
718
719 if (sign < 0)
720 {
721 result |= 0x8000000000000000LL;
722 }
723 value = *(double*)&result;
724 }
725
726
727 template <int N>
toDouble()728 double Rational<N>::toDouble() const
729 {
730 double d = 0.;
731 convertTo(d);
732 return d;
733 }
734
735 #endif
736