common warning id for double->object conversion

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

common warning id for double->object conversion

Colin Macdonald-2
[moving to maintainers list]

Summary: if you do `sym(1/3)` instead of `sym(1)/3`, we give a warning.

On 22/06/16 08:48, Oliver Heimlich wrote:
> There is the exactly same issue in the interval package. If you want
> to implement this feature in the construtors (maybe with a regexp
> to identify fractions and decimal numbers) we should use the same
> warning id.

Good idea.  Do you think its appropriate to use the "Octave" namespace?

Maybe something lke:

2. warning("Octave:possible-precision-loss", <custom message>)
3. warning("Octave:lossy-object-from-double", ...)

For `sym` objects its currently:

warning('OctSymPy:sym:rationalapprox', ...
   'Using rat() heuristics for double-precision input (is this what you
wanted?)');

(but I'm happy to change it).

Colin

Reply | Threaded
Open this post in threaded view
|

Re: common warning id for double->object conversion

LachlanA
Colin Macdonald-2 wrote
On 22/06/16 08:48, Oliver Heimlich wrote:
>  we should use the same
> warning id.

Good idea.  Do you think its appropriate to use the "Octave" namespace?
What is the purpose of the "Octave" namespace?  If it were up to me, only Octave core warnings would use the Octave namespace, and all forge packages would use their own namespace (such as "Forge:") for new warnings.  Packages could still throw existing Octave: namespace warnings.

My particular reason for that is that I would like to add a system that warns users if they try to set a non-existent warning in the Octave namespace (such as warning people when  Octave:automatic-broadcast  disappeared).  That is not possible if external entities can create their own warnings in the Octave: namespace.

Cheers,
Lachlan
Reply | Threaded
Open this post in threaded view
|

Re: common warning id for double->object conversion

Oliver Heimlich
In reply to this post by Colin Macdonald-2
On 22.06.2016 20:07, Colin Macdonald wrote:
> [moving to maintainers list]
>
> Summary: if you do `sym(1/3)` instead of `sym(1)/3`, we give a warning.

How do you decide whether to give a warning? If the parameter is no
integer? There are some fractions which have no rounding errors, e. g.
0.5, 0.25, 0.125, … and sums thereof.

On 22.06.2016 23:34, Colin Macdonald wrote:
> On 22/06/16 11:26, Reik Reid wrote:
>> If vpa() behaved the same way as sym(), would leaving out the quotes be
>> safe for all cases of constant numerical expressions? Is that a
>> desirable behavior?
>
> There is a relatively small set of values were its safe to leave off the
> quotes, for both sym and vpa.  That set is "small" integers, inf, nan,
> and pi.  The latter just for convenience (might have been a bad idea).

It's a difficult topic:

1. Even small integers might be the result of lost digits, e. g.
1.0000000000000001.

2. Experts might argue that inf is not infinity, but overflow of a big
value, e. g. 1e309.

3. nans are complicated already, e. g. 1e-324 / 1e-324.

4. yeah, pi might be problematic as well if the user expects to use the
approximate floating point value returned by pi () instead of π.

> On 22/06/16 08:48, Oliver Heimlich wrote:
>> There is the exactly same issue in the interval package. If you want
>> to implement this feature in the construtors (maybe with a regexp
>> to identify fractions and decimal numbers) we should use the same
>> warning id.
>
> Good idea.  Do you think its appropriate to use the "Octave" namespace?
>
> Maybe something lke:
>
> 2. warning("Octave:possible-precision-loss", <custom message>)
> 3. warning("Octave:lossy-object-from-double", ...)
>
> For `sym` objects its currently:
>
> warning('OctSymPy:sym:rationalapprox', ...
>   'Using rat() heuristics for double-precision input (is this what you
> wanted?)');
>
> (but I'm happy to change it).
>
> Colin

We could stick to the official naming from IEEE 754, which is the
“inexact” exception. I propose one of the following:
    warning("Octave:inexact-argument", …)
    warning("numeric:inexact-argument", …)
    warning("double:inexact-argument", …)

I am still not sure how do decide whether to trigger the warning.
Basically, we want to trigger the warning if some expression for the
input argument has triggered the “inexact” floating point exception.

However, we have no access to this information. What we have:
a. the floating point value of the input argument,
b. the expression for the input argument as a string (“argn” variable)

The argn variable might hide that the inexactness has happened before
calling the function. However, in this case I would not want to have a
warning. For example,
x = 0.1
sym (x)

Also the argn variable might be a complicated expression which produces
inexactness, e. g. 1 / (2 + 8). We don't want to handle these cases.
However, we want to handle basic matrix expressions like [1 2; 3 0.1]

Points 1 – 4 from above show that it is not possible to conclude from
the parameter's value alone, whether inexactness has occurred. If in
addition, we use the parameter's expression (argn), we can detect simple
cases at least. So what do we have to do to eliminate false positives?

1. Check if the parameter has a scalar value of type double (binary64).
2. Check if the parameter expression is either a decimal number of the
form [+-]d[.]d[[eE][+-]d] or a fraction of the form [+-]d / d. Matrix
expressions with square brackets, comma, and semicolon must be
considered as well.
3. Check whether the value is the result of inexact conversion.

The last point is complicated/costly. It gets even more complicated when
you want to cover non-scalar arguments as well, e. g. sym ([0.1, 0.2]).

So, maybe above goals are too ambitious. We could lower the quality of
step 3 and only check whether the parameter's value is not an integer
and uses more than N mantissa bits on the fractional part of the value
(N = 26 should be reasonable -- half the double precision). Then it is
possible to decide this problem in many common cases and create an
internal function.

__check_inexact_arg__ (x, argn(1, :))
__check_inexact_arg__ (y, argn(2, :))

function __check_inexact_arg__ (val, expression)
if (isa (val, 'double') && warning ("query", "numeric:inexact-argument"))
  if (rem (val, pow2 (-26)) != 0)
    if (regexp (expression, …))
      warning ("numeric:inexact-argument", …)
    endif
  endif
endif
endfunction

This is quite cheap to check and limits false positives to cases where
the user has entered more than 8 decimal digits and the number happens
to be exact. We don't detect some cases with lengthy numbers, e. g.
1.0000000000000001.

Oliver

Reply | Threaded
Open this post in threaded view
|

Re: common warning id for double->object conversion

Colin Macdonald-2
On 22/06/16 18:07, Oliver Heimlich wrote:
> How do you decide whether to give a warning? If the parameter is no
> integer? There are some fractions which have no rounding errors, e. g.
> 0.5, 0.25, 0.125, … and sums thereof.

I do this:

https://github.com/cbm755/octsympy/blob/master/inst/%40sym/private/magic_double_str.m

Its very simple.  I don't care if 0.25 has an exact bit representation:
"sym(0.25)" is bad code, one should use "sym(1)/4".  And generally I
don't think symbolic users should be passing double values from other
code into sym, so an aggressive warning is good.  (I'm sure there are
valid use cases, but I've not seen one that outweighs the educational
aspect for new users).

vpa is a little different: perhaps that's why I never added a warning
there before.  One can imagine feeding double's from some other part of
a code into vpa code (e.g., as an initial guess to vpasolve).  Instead
there is a prominent warning in the docs.  But since a new user was
confused by vpa(1/3)---*the same example in the docs*---I'm rethinking
that choice...

> 4. yeah, pi might be problematic as well if the user expects to use the
> approximate floating point value returned by pi () instead of π.

An expert use; not too worried about that, e.g., could do "vpa(vpa(pi,
16), 64)".

> We could stick to the official naming from IEEE 754, which is the
> “inexact” exception. I propose one of the following:
>     warning("Octave:inexact-argument", …)
>     warning("numeric:inexact-argument", …)
>     warning("double:inexact-argument", …)

Sounds reasonable.  I think I like either "numeric:" or "double:".  Is
it appropriate for me to use such an IEEE754 convention even if I stick
with my much-simplified tests (above)?  That is, may I raise such a
thing on sym(0.25)?


Thanks for the detailed thoughts.  For syms, I might consider using
something like your function *after* the warning...  Right now, sym has
some heuristics using rat() that prefers "short" rationals or
rational*pi.  Example:

 >> a = pi/8 + 1000*eps
a =    0.392699081698946
 >> sym(a)
warning: Using rat() heuristics for double-precision input (is this what
you wanted?)
warning: called from
     sym at line 225 column 7
ans = (sym)

   π
   ─
   8

(The alternative is to give them back the exact real number
corresponding to the double precision value they pass in...)

Colin