Mercurial > octave
comparison liboctave/util/oct-string.cc @ 30867:014030798d5e stable
Avoid issues when converting large integers to floating point (bug #62212).
* libinterp/corefcn/oct-stream.cc (get_size),
libinterp/corefcn/xpow.cc (xisint),
libinterp/octave-value/ov-base.cc (INT_CONV_METHOD),
libinterp/octave-value/ov.cc (check_colon_operand, range_numel (T, double, T)),
liboctave/numeric/lo-mappers.cc (nint_big, nint),
liboctave/util/oct-inttypes.cc (emulate_mop,
operator - (const double, const octave_uint64)),
liboctave/util/oct-string.cc (rational_approx): Take into account that the
maximum value of (signed or unsigned) integers might change its value if
converted to floating point. In comparisons, check against the first value
*outside* the range of the integer type instead of the last value *inside* its
range.
author | Markus Mützel <markus.muetzel@gmx.de> |
---|---|
date | Mon, 28 Mar 2022 19:27:35 +0200 |
parents | 796f54d4ddbf |
children | 79edd49a5a97 |
comparison
equal
deleted
inserted
replaced
30864:5fa3d8f0dcb3 | 30867:014030798d5e |
---|---|
614 std::string s; | 614 std::string s; |
615 | 615 |
616 if (len <= 0) | 616 if (len <= 0) |
617 len = 10; | 617 len = 10; |
618 | 618 |
619 static const T out_of_range_top | |
620 = static_cast<T>(std::numeric_limits<int>::max ()) + 1.; | |
621 static const T out_of_range_bottom | |
622 = static_cast<T>(std::numeric_limits<int>::min ()) - 1.; | |
619 if (octave::math::isinf (val)) | 623 if (octave::math::isinf (val)) |
620 { | 624 { |
621 if (val > 0) | 625 if (val > 0) |
622 s = "1/0"; | 626 s = "1/0"; |
623 else | 627 else |
624 s = "-1/0"; | 628 s = "-1/0"; |
625 } | 629 } |
626 else if (octave::math::isnan (val)) | 630 else if (octave::math::isnan (val)) |
627 s = "0/0"; | 631 s = "0/0"; |
628 else if (val < std::numeric_limits<int>::min () | 632 else if (val <= out_of_range_bottom || val >= out_of_range_top |
629 || val > std::numeric_limits<int>::max () | |
630 || octave::math::x_nint (val) == val) | 633 || octave::math::x_nint (val) == val) |
631 { | 634 { |
632 std::ostringstream buf; | 635 std::ostringstream buf; |
633 buf.flags (std::ios::fixed); | 636 buf.flags (std::ios::fixed); |
634 buf << std::setprecision (0) << octave::math::round (val); | 637 buf << std::setprecision (0) << octave::math::round (val); |
654 T step = octave::math::round (flip); | 657 T step = octave::math::round (flip); |
655 T nextn = n; | 658 T nextn = n; |
656 T nextd = d; | 659 T nextd = d; |
657 | 660 |
658 // Have we converged to 1/intmax ? | 661 // Have we converged to 1/intmax ? |
659 if (std::abs (flip) > static_cast<T> (std::numeric_limits<int>::max ())) | 662 if (std::abs (flip) > out_of_range_top) |
660 { | 663 { |
661 lastn = n; | 664 lastn = n; |
662 lastd = d; | 665 lastd = d; |
663 break; | 666 break; |
664 } | 667 } |
685 { | 688 { |
686 if (buf.str ().length () > static_cast<unsigned int> (len)) | 689 if (buf.str ().length () > static_cast<unsigned int> (len)) |
687 break; | 690 break; |
688 } | 691 } |
689 | 692 |
690 if (std::abs (n) > std::numeric_limits<int>::max () | 693 if (std::abs (n) >= out_of_range_top |
691 || std::abs (d) > std::numeric_limits<int>::max ()) | 694 || std::abs (d) >= out_of_range_top) |
692 break; | 695 break; |
693 | 696 |
694 s = buf.str (); | 697 s = buf.str (); |
695 } | 698 } |
696 | 699 |