python - Do numerical programming languages distinguish between a "largest finite number" and "infinity"? -


question motivation:

in standard numerical languages of aware (e.g. matlab, python numpy, etc.), if, example, take exponential of modestly large number, output infinity result of numerical overflow. if multiplied 0, nan. separately, these steps reasonable enough, reveal logical mistake in implementation of math. first number resulting overflow known finite , want result of multiplication 0 large finite number 0.

explicitly:

>>> import numpy np >>> np.exp(709)*0 0.0 >>> np.exp(710)*0 nan 

i imagine here introduce notion of "largest finite value" (lfv) have following properties:

  • lfv default numerical overflow otherwise round infinity
  • lfv < infinity
  • any explicit number < lfv (for example if lev stands "largest explicit value", lev
  • (matlab detail: realmax < lfv)
  • lfv*0 = 0

on other hand, infinity should not redefined in way described lfv. not make sense 0 *infinity = 0...appropriately, current standard implementation of infinity yields nan in setting. also, there arises need initialize numbers infinity , you'd want result of numerical operation, 1 yielded lfv strictly less initialized value (this convenient logical statements). i'm sure other situations exist proper infinity necessary -- point infinity should not redefined have of lfv properties above.

the question:

i want know if there language uses scheme , if there problems such scheme. problem not arise in proper math since there aren't these numerical limits on size of numbers, think real problem when implementing consistent mathematics in programming languages. essentially, lfv, think want shorthand open interval between largest explicit value , infinity lfv = (lev,infinity), maybe intuition wrong.

update: in comments, people seem objecting little utility of issue i'm bringing up. question arises not because many related issues occur, rather because same issue arises in many different settings. talking people data analysis, enough contributes runtime errors when training/fitting models. question why isn't handled numerical languages. comments, i'm gathering people write languages don't see utility of handling things way. in opinion, when specific issues occur enough people using language, might make sense handle exceptions in principled way each user doesn't have to.

so... got curious , dug around little.

as mentioned in comments, "largest finite value" kind of exists in ieee 754, if consider exception status flags. value of infinity overflow flag set corresponds proposed lfv, difference flag available read out after operation, instead of being stored part of value itself. means have manually check flag , act if overflow occurs, instead of having lfv*0 = 0 built in.

there quite interesting paper on exception handling , support in programming languages. quote:

the ieee 754 model of setting flag , returning infinity or quiet nan assumes user tests status (or @ least appropriately.) diagnosing original problem requires user check results exceptional values, in turn assumes percolated through operations, erroneous data can flagged. given these assumptions, should work, unfortunately not realistic.

the paper bemoans poor support floating point exception handling, in c99 , java (i'm sure other languages aren't better though). given in spite of this, there no major efforts fix or create better standard, me seems indicate ieee 754 , support are, in sense, "good enough" (more on later).


let me give solution example problem demonstrate something. i'm using numpy's seterr make raise exception on overflow:

import numpy np  def exp_then_mult_naive(a, b):     err = np.seterr(all='ignore')     x = np.exp(a) * b     np.seterr(**err)     return x  def exp_then_mult_check_zero(a, b):     err = np.seterr(all='ignore', over='raise')     try:         x = np.exp(a)         return x * b     except floatingpointerror:         if b == 0:             return 0         else:             return exp_then_mult_naive(a, b)     finally:         np.seterr(**err)  def exp_then_mult_scaling(a, b):     err = np.seterr(all='ignore', over='raise')     e = np.exp(1)     while abs(b) < 1:         try:             x = np.exp(a) * b             break         except floatingpointerror:             -= 1             b *= e     else:         x = exp_then_mult_naive(a, b)     np.seterr(**err)     return x  large = np.float_(710) tiny = np.float_(0.01) 0 = np.float_(0.0)  print('naive: e**710 * 0 = {}'.format(exp_then_mult_naive(large, zero))) print('check zero: e**710 * 0 = {}'     .format(exp_then_mult_check_zero(large, zero))) print('check zero: e**710 * 0.01 = {}'     .format(exp_then_mult_check_zero(large, tiny))) print('scaling: e**710 * 0.01 = {}'.format(exp_then_mult_scaling(large, tiny)))  # output: # naive: e**710 * 0 = nan # check zero: e**710 * 0 = 0 # check zero: e**710 * 0.01 = inf # scaling: e**710 * 0.01 = 2.233994766161711e+306 
  • exp_then_mult_naive did: expression overflow multiplied 0 , nan.
  • exp_then_mult_check_zero catches overflow , returns 0 if second argument 0, otherwise same naive version (note inf * 0 == nan while inf * positive_value == inf). best if there lfv constant.
  • exp_then_mult_scaling uses information problem results inputs other 2 couldn't deal with: if b small, can multiply e while decrementing a without changing result. if np.exp(a) < np.inf before b >= 1, result fits. (i know check if fits in 1 step instead of using loop, easier write right now.)

so have situation solution doesn't require lfv able provide correct results more input pairs 1 does. advantage lfv has here using fewer lines of code while still giving correct result in 1 particular case.

by way, i'm not sure thread safety seterr. if you're using in multiple threads different settings in each thread, test out before avoid headache later.


bonus factoid: original standard stipulated should able register trap handler would, on overflow, given result of operation divided large number (see section 7.3). allow carry on computation, long keep in mind value larger. although guess become minefield of wtf in multithreaded environment, never mind didn't find support it.


to "good enough" point above: in understanding, ieee 754 designed general purpose format, usable practically application. when "the same issue arises in many different settings", (or @ least was) apparently not enough justify inflating standard.

let me quote wikipedia article:

[...] more esoteric features of ieee 754 standard discussed here, such extended formats, nan, infinities, subnormals etc. [...] designed give safe robust defaults numerically unsophisticated programmers, in addition supporting sophisticated numerical libraries experts.

putting aside that, in opinion, having nan special value bit of dubious decision, adding lfv isn't going make easier or safer "numerically unsophisticated", , doesn't allow experts couldn't already.

i guess bottom line representing rational numbers hard. ieee 754 pretty job of making simple lot of applications. if yours isn't 1 of them, in end you'll have deal hard stuff either

  • using higher precision float, if available (ok, one's pretty easy),
  • carefully selecting order of execution such don't overflows in first place,
  • adding offset values if know they're going large,
  • using arbitrary-precision representation can't overflow (unless run out of memory), or
  • something else can't think of right now.

Comments

Popular posts from this blog

asp.net mvc - SSO between MVCForum and Umbraco7 -

Python Tkinter keyboard using bind -

ubuntu - Selenium Node Not Connecting to Hub, Not Opening Port -