Mercurial > octave
diff libinterp/operators/op-mi.cc @ 28588:ee9b1081471f
allow integer constants > flintmax to be represented exactly (bug #45945)
* ov-magic-int.h, ov-magic-int.cc: New files to provide "magic"
integer data type that can store integer constants larger than
flintmax but that behaves like a double constant in nearly all cases.
The primary exception is when the value is processed by the int64 and
uint64 functions.
* libinterp/octave-value/module.mk: Update.
* op-mi.cc: New file. Provide unary + and - operators for magic
integers so that explicit positive or negative magic integers will
work as expected.
* libinterp/operators/module.mk: Update.
* ov-base.h (octave_base_value::is_magic_int): New virtual function.
* ov.h, ov.cc (octave_value::is_magic_int): New function.
(octave_value::storable_value, octave_value::make_storable_value):
Also handle magic integer values.
(octave_value::install_types): Install octave_magic_int and
octave_magic_uint types.
* lex.ll (flintmax): New static function.
(base_lexer::handle_number<10>): Create magic integers from constants
that contain only digits and have values in the range flintmax to
std::numeric_limits<uint64_t>::max().
* pt-eval.cc (tree_evaluator::bind_ans): Display stored value.
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Mon, 20 Jul 2020 17:43:16 -0400 |
parents | |
children | 7854d5752dd2 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libinterp/operators/op-mi.cc Mon Jul 20 17:43:16 2020 -0400 @@ -0,0 +1,119 @@ +//////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2020 The Octave Project Developers +// +// See the file COPYRIGHT.md in the top-level directory of this +// distribution or <https://octave.org/copyright/>. +// +// This file is part of Octave. +// +// Octave is free software: you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Octave is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Octave; see the file COPYING. If not, see +// <https://www.gnu.org/licenses/>. +// +//////////////////////////////////////////////////////////////////////// + +#if defined (HAVE_CONFIG_H) +# include "config.h" +#endif + +#include <iostream> + +#include "errwarn.h" +#include "ops.h" +#include "ov-magic-int.h" +#include "ov-typeinfo.h" +#include "ov.h" + +// Magic integer unary ops. Only + and - are allowed so that +// expressions like +// +// int64 (-9007199254740994) +// +// produce proper int64 constants. + +static octave_value +oct_unop_unsigned_uplus (const octave_base_value& a) +{ + const octave_magic_uint& v = dynamic_cast<const octave_magic_uint&> (a); + // no-op. + // FIXME: but can we do this just by incrementing the reference count? + return octave_value (v.clone ()); +} + +static octave_value +oct_unop_unsigned_uminus (const octave_base_value& a) +{ + const octave_magic_uint& v = dynamic_cast<const octave_magic_uint&> (a); + + // We are storing a uint64 value, so some fakery is needed here. + // Is there a better way? + + octave_uint64 val = v.uint64_scalar_value (); + + uint64_t ival = val.value (); + + static const uint64_t max_val + = static_cast<uint64_t> (std::numeric_limits<int64_t>::max ()); + + static const uint64_t max_val_p1 = max_val + 1; + + if (ival <= max_val) + { + int64_t signed_ival = ival; + return octave_value (new octave_magic_int (-signed_ival)); + } + + if (ival == max_val_p1) + { + // Correctly capture intmin. For example, negating uint8(128) + // should return int8(-128) but converting directly to int8 and + // negating will not return the correct result. + + static const int64_t min_signed_ival + = std::numeric_limits<int64_t>::min (); + + return octave_value (new octave_magic_int (min_signed_ival)); + } + + return octave_value (-static_cast<double> (ival)); +} + +static octave_value +oct_unop_signed_uplus (const octave_base_value& a) +{ + const octave_magic_int& v = dynamic_cast<const octave_magic_int&> (a); + // no-op. + // FIXME: but can we do this just by incrementing the reference count? + return octave_value (v.clone ()); +} + +static octave_value +oct_unop_signed_uminus (const octave_base_value& a) +{ + const octave_magic_int& v = dynamic_cast<const octave_magic_int&> (a); + + octave_int64 val = v.int64_scalar_value (); + + return octave_value (new octave_magic_int (-val)); +} + +void +install_mi_ops (octave::type_info& ti) +{ + INSTALL_UNOP_TI (ti, op_uplus, octave_magic_uint, unsigned_uplus); + INSTALL_UNOP_TI (ti, op_uminus, octave_magic_uint, unsigned_uminus); + + INSTALL_UNOP_TI (ti, op_uplus, octave_magic_int, signed_uplus); + INSTALL_UNOP_TI (ti, op_uminus, octave_magic_int, signed_uminus); +}