changeset 33200:9f97974976cd

Allow integer inputs greater than 999999 to jsonencode (bug #65447) * NEWS.10.md: Announce that integers and flints are now output without ".0" suffix. * jsonencode.cc (encode_numeric): Remove test for floating point integers being below 999999 in order to write out as integer. Add new "else if" block to process integer inputs and write them as integers. * jsonencode.cc (encode): Better comments for if/else if tree decoding input type. * jsonencode_BIST.tst: New tests for integer inputs and for flints greater than 1e6.
author Rik <rik@octave.org>
date Tue, 12 Mar 2024 21:47:48 -0700
parents 297fd823a953
children cab636a9c37b
files etc/NEWS.10.md libinterp/corefcn/jsonencode.cc test/json/jsonencode_BIST.tst
diffstat 3 files changed, 31 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/etc/NEWS.10.md	Tue Mar 12 14:27:13 2024 -0700
+++ b/etc/NEWS.10.md	Tue Mar 12 21:47:48 2024 -0700
@@ -22,6 +22,9 @@
 The function no longer accepts complex inputs and will emit an error for these
 inputs.
 
+- `jsonencode` now outputs integers and floating point integers without ".0"
+  suffix.
+
 ### Graphical User Interface
 
 ### Graphics backend
--- a/libinterp/corefcn/jsonencode.cc	Tue Mar 12 14:27:13 2024 -0700
+++ b/libinterp/corefcn/jsonencode.cc	Tue Mar 12 21:47:48 2024 -0700
@@ -65,13 +65,13 @@
     {
       double value = obj.scalar_value ();
 
-      // Any numeric input from the interpreter will be in double type so in
-      // order to detect ints, we will check if the floor of the input and the
-      // input are equal using fabs (A - B) < epsilon method as it is more
-      // accurate.  If value > 999999, MATLAB will encode it in scientific
-      // notation (double).
-      if (fabs (floor (value) - value) < std::numeric_limits<double>::epsilon ()
-          && fabs (value) <= 999999)
+      // Detect floating point numbers which are actually integers by checking
+      // whether the number and the integer portion of the number are the same
+      // to within eps.
+      // FIXME: If value > 999999, MATLAB will encode it in scientific
+      // notation, but rapidJSON will output all digits.
+      if (fabs (trunc (value) - value) < std::numeric_limits<double>::epsilon ())
+
         writer.Int64 (value);
       // Possibly write NULL for non-finite values (-Inf, Inf, NaN, NA)
       else if (ConvertInfAndNaN && ! octave::math::isfinite (value))
@@ -79,6 +79,21 @@
       else
         writer.Double (value);
     }
+  else if (obj.isinteger ())
+    {
+       if (obj.is_uint64_type ())
+         {
+            uint64_t value = obj.uint64_value ();
+            writer.Uint64 (value);
+         }
+       else
+         {
+            // Write all other integers as 64-bit values and let RapidJSON
+            // determine number of digits to keep.
+            int64_t value = obj.int64_value ();
+            writer.Int64 (value);
+         }
+    }
   else if (obj.is_bool_scalar ())
     writer.Bool (obj.bool_value ());
   else
@@ -404,9 +419,10 @@
 encode (T& writer, const octave_value& obj, const bool& ConvertInfAndNaN)
 {
   if (obj.is_real_scalar ())
+    // Numeric scalars.
     encode_numeric (writer, obj, ConvertInfAndNaN);
-  // As I checked for scalars, this will detect numeric & logical arrays
   else if (obj.isnumeric () || obj.islogical ())
+    // Numeric and logical arrays.
     encode_array (writer, obj, ConvertInfAndNaN, obj.dims ());
   else if (obj.is_string ())
     encode_string (writer, obj, obj.dims ());
--- a/test/json/jsonencode_BIST.tst	Tue Mar 12 14:27:13 2024 -0700
+++ b/test/json/jsonencode_BIST.tst	Tue Mar 12 21:47:48 2024 -0700
@@ -17,6 +17,8 @@
 %! assert (isequal (jsonencode (50.025), '50.025'));
 %! %% FIXME: Uncomment when bug #64960 is fixed
 %! %% assert (isequal (jsonencode (single (50.025)), '50.025'));
+%! assert (isequal (jsonencode (uint64 (1e6)), '1000000'));
+%! assert (isequal (jsonencode (int64 (-1e6)), '-1000000'));
 %! assert (isequal (jsonencode (NaN), 'null'));
 %! assert (isequal (jsonencode (NA), 'null'));    % Octave-only test
 %! assert (isequal (jsonencode (Inf), 'null'));
@@ -112,6 +114,8 @@
 %!testif HAVE_RAPIDJSON
 %! assert (isequal (jsonencode ([]), '[]'));
 %! assert (isequal (jsonencode ([1, 2, 3, 4]), '[1,2,3,4]'));
+%! % Matlab encodes flints with values above 1e6-1 in scientific notation.  Octave writes integers.
+%! assert (isequal (jsonencode ([1.23e6, 2]), '[1230000,2]'));
 %! assert (isequal (jsonencode ([true; false; true]), '[true,false,true]'));
 
 %% Test arrays