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