<body><div id="__MailbirdStyleContent" style="font-size: 10pt;font-family: Arial;color: #000000;text-align: left" dir="ltr">
                                        <div>Hi Nicolas --</div><div><br></div>+1<div><br></div><div>Best,</div><div>Marcel</div><div class="mb_sig"></div><blockquote class='history_container' type='cite' style='border-left-style:solid;border-width:1px; margin-top:20px; margin-left:0px;padding-left:10px;'>
                        <p style='color: #AAAAAA; margin-top: 10px;'>Am 26.04.2022 13:24:38 schrieb commits@source.squeak.org <commits@source.squeak.org>:</p><div style='font-family:Arial,Helvetica,sans-serif'>Nicolas Cellier uploaded a new version of Kernel to project The Inbox:<br>http://source.squeak.org/inbox/Kernel-nice.1462.mcz<br><br>==================== Summary ====================<br><br>Name: Kernel-nice.1462<br>Author: nice<br>Time: 26 April 2022, 1:24:22.90052 pm<br>UUID: e7c0b097-55c5-8e43-9231-9164aa4a8b4e<br>Ancestors: Kernel-nice.1461<br><br>Detect case of overflow in intermediate computations of Complex arithmetic (* and /), and fallback to more secured algorithm, with appropriate scaling and careful order of operations.<br><br>Rationale: the strategy consisting in letting us - programmers - choose our punition, always use slower and less accurate divideSecureBy:, or take the risk of using a faster but potentially flawed #/ is too heavy for our shoulders. This is too high a tribute to prematured optimization. A better strategy is to provide arithmetic operations that will deliver correct results when possible, and let us develop ou own FastComplex specialization if we really want to live at risks for a few CPU cycles.<br><br>An effort is made here to make the additional cost bearable.<br><br>Additional cost induced by handling of exceptional cases does not count, because replacing an incorrect result with a correct one is priceless.<br><br>Additional cost induced by detection of those conditions in non exceptional case is not that high:<br>- isFinite is very cheap for exact arithmetic,<br>- and just 1 op and 1 comparison for Float<br><br>Note that in #/ implementation, we cannot test case of null denom in precondition because denom might be non null in exact arithmetic, but later vanishing due to underflow in automatic asFloat conversion. We thus have to protect with ZeroDivide handling.<br><br>Again, a FloatComplex specialization could deal with this kind of optimization if really necessary.<br><br>=============== Diff against Kernel-nice.1461 ===============<br><br>Item was changed:<br>  ----- Method: Complex>>* (in category 'arithmetic') -----<br>  * anObject<br>     "Answer the result of multiplying the receiver by aNumber."<br>+        | a b c d x y newReal newImaginary |<br>-         | a b c d newReal newImaginary |<br>      anObject isComplex<br>            ifTrue:<br>                       [a := self real.<br>                      b := self imaginary.<br>                          c := anObject real.<br>                   d := anObject imaginary.<br>                      newReal := (a * c) - (b * d).<br>                         newImaginary := (a * d) + (b * c).<br>+                   ((newReal isFinite not or: [newImaginary isFinite not]) and: [self isZero not and: [anObject isZero not]])<br>+                           ifTrue:<br>+                                      ["intermediate computations do overflow, but the product may be finite, retry with scaling"<br>+                                        x := a abs max: b abs.<br>+                                       y := c abs max: d abs.<br>+                                       a := a / x.<br>+                                  b := b / x.<br>+                                  c := c / y.<br>+                                  d := d / y.<br>+                                  newReal := (a * c) - (b * d) * x * y.<br>+                                        newImaginary := (a * d) + (b * c) * x * y].<br>                   ^ Complex real: newReal imaginary: newImaginary]<br>              ifFalse:<br>                      [^ anObject adaptToComplex: self andSend: #*]!<br><br>Item was changed:<br>  ----- Method: Complex>>/ (in category 'arithmetic') -----<br>  / anObject<br>          "Answer the result of dividing receiver by aNumber"<br>+        | a b c d newReal newImaginary denom |<br>-       | a b c d newReal newImaginary |<br>      anObject isComplex ifTrue:<br>            [a := self real.<br>              b := self imaginary.<br>                  c := anObject real.<br>           d := anObject imaginary.<br>+             denom := c squared + d squared.<br>+              [newReal := ((a * c) + (b * d)) / denom.<br>+             newImaginary := ((b * c) - (a * d)) / denom]<br>+                         on: ZeroDivide do:<br>+                           [:exc |<br>+                              "This might be a case of underflow - resume with a value that will result in a secured retry"<br>+                              exc resume: Float infinity].<br>+                 (denom isFinite and: [newReal isFinite and: [newImaginary isFinite]])<br>+                        ifFalse:<br>+                             ["case of overflow, retry securedly"<br>+                               ^self divideSecureBy: anObject].<br>-             newReal := ((a * c) + (b * d)) / ((c * c) + (d * d)).<br>-                newImaginary := ((b * c) - (a * d)) / ((c * c) + (d * d)).<br>            ^ Complex real: newReal imaginary: newImaginary].<br>     ^ anObject adaptToComplex: self andSend: #/.!<br><br><br></div></blockquote>
                                        </div></body>