2525 Tuple ,
2626 )
2727
28+ from colour .constants import EPSILON
2829from colour .hints import Literal , cast
29- from colour .utilities import as_float , as_float_array , optional , tsplit , validate_method
30+ from colour .utilities import (
31+ as_float ,
32+ as_float_array ,
33+ optional ,
34+ runtime_warning ,
35+ tsplit ,
36+ validate_method ,
37+ )
3038
3139__author__ = "Colour Developers"
3240__copyright__ = "Copyright 2013 Colour Developers"
6775 "Warning Zero Conversion" ,
6876 "Ignore Limit Conversion" ,
6977 "Warning Limit Conversion" ,
78+ "Replace With Epsilon" ,
79+ "Warning Replace With Epsilon" ,
7080] = "Ignore Zero Conversion"
7181"""
7282Global variable storing the current *Colour* safe division function mode.
@@ -83,6 +93,8 @@ def get_sdiv_mode() -> (
8393 "Warning Zero Conversion" ,
8494 "Ignore Limit Conversion" ,
8595 "Warning Limit Conversion" ,
96+ "Replace With Epsilon" ,
97+ "Warning Replace With Epsilon" ,
8698 ]
8799):
88100 """
@@ -118,6 +130,8 @@ def set_sdiv_mode(
118130 "Warning Zero Conversion" ,
119131 "Ignore Limit Conversion" ,
120132 "Warning Limit Conversion" ,
133+ "Replace With Epsilon" ,
134+ "Warning Replace With Epsilon" ,
121135 ]
122136 | str
123137 ),
@@ -153,6 +167,8 @@ def set_sdiv_mode(
153167 "Warning Zero Conversion" ,
154168 "Ignore Limit Conversion" ,
155169 "Warning Limit Conversion" ,
170+ "Replace With Epsilon" ,
171+ "Warning Replace With Epsilon" ,
156172 ],
157173 validate_method (
158174 mode ,
@@ -165,6 +181,8 @@ def set_sdiv_mode(
165181 "Warning Zero Conversion" ,
166182 "Ignore Limit Conversion" ,
167183 "Warning Limit Conversion" ,
184+ "Replace With Epsilon" ,
185+ "Warning Replace With Epsilon" ,
168186 ),
169187 ),
170188 )
@@ -194,6 +212,8 @@ def __init__(
194212 "Warning Zero Conversion" ,
195213 "Ignore Limit Conversion" ,
196214 "Warning Limit Conversion" ,
215+ "Replace With Epsilon" ,
216+ "Warning Replace With Epsilon" ,
197217 ]
198218 | None
199219 ) = None ,
@@ -254,10 +274,16 @@ def sdiv(a: ArrayLike, b: ArrayLike) -> NDArrayFloat:
254274 finite floating point values representable by the division result
255275 :class:`numpy.dtype`. See :func:`numpy.nan_to_num` definition for more
256276 details.
257- - ``Warning Limit Conversion``: Zero-division occurs with a warning and
277+ - ``Warning Limit Conversion``: Zero-division occurs with a warning and
258278 NaNs or +/- infs values are converted to zeros or the largest +/-
259279 finite floating point values representable by the division result
260280 :class:`numpy.dtype`.
281+ - ``Replace With Epsilon``: Zero-division is avoided by replacing zero
282+ denominators with the machine epsilon value from
283+ :attr:`colour.constants.EPSILON`.
284+ - ``Warning Replace With Epsilon``: Zero-division is avoided by replacing
285+ zero denominators with the machine epsilon value from
286+ :attr:`colour.constants.EPSILON` with a warning.
261287
262288 Parameters
263289 ----------
@@ -295,6 +321,12 @@ def sdiv(a: ArrayLike, b: ArrayLike) -> NDArrayFloat:
295321 >>> with sdiv_mode("Warning Limit Conversion"):
296322 ... sdiv(a, b) # doctest: +SKIP
297323 array([ 0.00000000e+000, 1.00000000e+000, 1.79769313e+308])
324+ >>> with sdiv_mode("Replace With Epsilon"):
325+ ... sdiv(a, b) # doctest: +ELLIPSIS
326+ array([ 0.00000000e+00, 1.00000000e+00, ...])
327+ >>> with sdiv_mode("Warning Replace With Epsilon"):
328+ ... sdiv(a, b) # doctest: +ELLIPSIS
329+ array([ 0.00000000e+00, 1.00000000e+00, ...])
298330 """
299331
300332 a = as_float_array (a )
@@ -311,6 +343,8 @@ def sdiv(a: ArrayLike, b: ArrayLike) -> NDArrayFloat:
311343 "Warning Zero Conversion" ,
312344 "Ignore Limit Conversion" ,
313345 "Warning Limit Conversion" ,
346+ "Replace With Epsilon" ,
347+ "Warning Replace With Epsilon" ,
314348 ),
315349 )
316350
@@ -337,6 +371,14 @@ def sdiv(a: ArrayLike, b: ArrayLike) -> NDArrayFloat:
337371 elif mode == "warning limit conversion" :
338372 with np .errstate (divide = "warn" , invalid = "warn" ):
339373 c = np .nan_to_num (a / b )
374+ elif mode == "replace with epsilon" :
375+ b = np .where (b == 0 , EPSILON , b )
376+ c = a / b
377+ elif mode == "warning replace with epsilon" :
378+ if np .any (b == 0 ):
379+ runtime_warning ("Zero(s) detected in denominator, replacing with EPSILON." )
380+ b = np .where (b == 0 , EPSILON , b )
381+ c = a / b
340382
341383 return c
342384
0 commit comments