Wed 07 Jun 2017 07:42:35 PM UTC, comment #7:
I changed Octave's default precision to be 17 digits so that saving/restoring double values is now lossless by default. See http://hg.savannah.gnu.org/hgweb/octave/rev/31b1ef1ee585.
Closing report.
|
Tue 06 Jun 2017 08:07:37 PM UTC, comment #6:
Perhaps the simplest way to fix this would be to change the default save precision from 16 to 17. This is a configuration variable that can be altered with the save_precision() function call.
I verified with
and it works correctly.
If this is the right way forward, then the line to change is ls-oct-text.cc:68
|
Tue 06 Jun 2017 06:44:33 PM UTC, comment #5:
Checking with the Wikipedia article on single precision (https://en.wikipedia.org/wiki/Single-precision_floating-point_format), Octave needs to store at least 9 digits of precision. However, Octave has already set the precision to 16 for the stream so single values are being written with far more digits than necessary. This isn't that much of a problem, the file size can grow a bit large, but one would use a binary format anyways if space were an issue.
|
Tue 06 Jun 2017 06:15:49 PM UTC, comment #4:
Checking with the wikipedia article on the IEEE-754 standard (https://en.wikipedia.org/wiki/Double-precision_floating-point_format), I find that precision is 15-17 decimal digits. If Octave wants to guarantee lossless save/restore of values in text format it needs to be keeping 17 digits. See the quote below.
|
Tue 06 Jun 2017 04:43:22 PM UTC, comment #3:
Octave should potentially be concerned that values are not be stored accurately. I am not sure yet whether this is just a problem with ranges, or it is a general problem with all double values.
Currently, Octave uses the routine octave_write_double which internally relies on the C++ std::lib to format the output. This routine writes 16 digits of precision, which would appear to be correct.
However, as a hack, I changed the routine to use 17 digits of precision.
This fixes the issue, tst_save_range now returns 142 three times. I've attached the diff for reference.
So the remaining question is whether Octave should enhance octave_write_double to be more precise, whether only the save_ascii routine for range variables should be updated, or whether this is really a problem on the load side.
(file #40864)
|
Tue 06 Jun 2017 04:34:43 PM UTC, comment #2:
The root cause of this bug is round-off error in a series of calculations. The way the publish.m script works is to execute a block of code, checkpoint the current workspace by saving all the variables to a temporary file, format the resulting output for presentation, and then move to the next block of code. For the next block of code it restores the current workspace by loading the variables from the temporary file.
Before my patch, publish.m was just using save/load to restore context. Because there were no options, the file format used was that set by the 'save_default_options" command. The default for this is '-text' which uses Octave's text format. Unfortunately, it appears that this format does not always accurately store range variables. To see this, I created the file tst_save_range.m which is attached. The code is
The output is
By using a different format, such as '-binary' or '-v7', the code will work. My immediate fix for publish.m was to switch to always using '-binary' format for saving intermediate variables.
|
Tue 06 Jun 2017 03:59:14 PM UTC, comment #1:
Confirmed. This turns out to be a very subtle bug.
I've pushed a solution for publish on the stable branch here (http://hg.savannah.gnu.org/hgweb/octave/rev/8133a5041662). This will be a part of the 4.2.2 bug fix release if there is one, or it will be a part of the next major release 4.4.0. Since the change was only to an m-file you can download the file and replace your local copy if you need an immediate fix.
I'm adding jwe to the CC list for a continued discussion about the root cause of this bug.
|
Sun 04 Jun 2017 01:06:29 PM UTC, original submission:
Publishing the following code with publish('test.m') produces incorrect results.
Expected result:
The output of the numel() calls should be the same each time (142). Running the code from the octave command line produces this result but using the publish() function does not.
Actual result:
The last section break removes the last element from the Ms vector which causes the last numel() call to return 141 instead of 142.
Further information:
I am running Arch Linux.
The bug does not get triggered if you change the first three lines to
|