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 multiplied0
,nan
.exp_then_mult_check_zero
catches overflow , returns0
if second argument0
, otherwise same naive version (noteinf * 0 == nan
whileinf * positive_value == inf
). best if there lfv constant.exp_then_mult_scaling
uses information problem results inputs other 2 couldn't deal with: ifb
small, can multiply e while decrementinga
without changing result. ifnp.exp(a) < np.inf
beforeb >= 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
Post a Comment