Nicolas Cellier uploaded a new version of Kernel to project The Trunk:
http://source.squeak.org/trunk/Kernel-nice.1229.mcz
==================== Summary ====================
Name: Kernel-nice.1229
Author: nice
Time: 9 May 2019, 9:10:10.673329 am
UUID: 4836a3a9-d962-4d8f-9180-5285b8e7c96a
Ancestors: Kernel-cmm.1228
Fix (0 bitShift: 100) is not normalized
(0 bitShift: 100) class = LargePositiveInteger.
Why is it not normalized?
First, primitiveBitShift (17) fails because shift is longer than SmallInteger bit length (maybe it should not?), then bitShiftMagnitude: (primDigitBitShiftMagnitude:) does not normalize a left shift result, assuming that primitive 17 already did the trivial work if result were a SmallInteger.
Why is normalization important?
because non normalized Integers do not behave like SmallInteger and can cause all sort of undefined behavior (I had an infinite loop because of that)
How to fix?
just handle the case in primitive fallback code
While at it:
Do not use bitShiftMagnitude: when we do not need to (case of left shift are equivalent to bitShift:), because playing with not normalized results may lead to undefined behavior.
=============== Diff against Kernel-cmm.1228 ===============
Item was changed:
----- Method: LargePositiveInteger>>digitMul22: (in category 'private') -----
digitMul22: anInteger
"Multiply after decomposing each operand in two parts, using Karatsuba algorithm.
Karatsuba perform only 3 multiplications, leading to a cost O(n^3 log2)
asymptotically better than super O(n^2) for large number of digits n.
See https://en.wikipedia.org/wiki/Karatsuba_algorithm"
| half xLow xHigh yLow yHigh low mid high |
"Divide each integer in two halves"
half := (anInteger digitLength + 1 bitShift: -1) bitClear: 2r11.
xLow := self lowestNDigits: half.
xHigh := self butLowestNDigits: half.
yLow := anInteger lowestNDigits: half.
yHigh := anInteger butLowestNDigits: half.
"Karatsuba trick: perform with 3 multiplications instead of 4"
low := xLow multiplyByInteger: yLow.
high := xHigh multiplyByInteger: yHigh.
mid := high + low + (xHigh - xLow multiplyByInteger: yLow - yHigh).
"Sum the parts of decomposition"
^(high isZero
ifTrue: [low]
+ ifFalse: [(high bitShift: 16*half)
- ifFalse: [(high bitShiftMagnitude: 16*half)
inplaceAddNonOverlapping: low digitShiftBy: 0])
+ + (mid bitShift: 8*half)!
- + (mid bitShiftMagnitude: 8*half)!
Item was changed:
----- Method: LargePositiveInteger>>squaredByHalf (in category 'private') -----
squaredByHalf
"Use a divide and conquer algorithm to perform the multiplication.
Split in two parts like Karatsuba, but economize 2 additions by using asymetrical product."
| half xHigh xLow low high mid |
"Divide digits in two halves"
half := self digitLength + 1 // 2 bitClear: 2r11.
xLow := self lowestNDigits: half.
xHigh := self butLowestNDigits: half.
"eventually use karatsuba"
low := xLow squared.
high := xHigh squared.
mid := xLow multiplyByInteger: xHigh.
"Sum the parts of decomposition"
+ ^(high bitShift: 16*half)
- ^(high bitShiftMagnitude: 16*half)
inplaceAddNonOverlapping: low digitShiftBy: 0;
+ + (mid bitShift: 8*half+1)
- + (mid bitShiftMagnitude: 8*half+1)
"
| a |
a := 440 factorial-1.
a digitLength.
self assert: a * a - a squaredKaratsuba = 0.
[Smalltalk garbageCollect.
[2000 timesRepeat: [a squaredKaratsuba]] timeToRun] value /
[Smalltalk garbageCollect.
[2000 timesRepeat: [a * a]] timeToRun] value asFloat
"!
Item was changed:
----- Method: SmallInteger>>bitShift: (in category 'bit manipulation') -----
bitShift: arg
"Primitive. Answer an Integer whose value is the receiver's value shifted
left by the number of bits indicated by the argument. Negative arguments
shift right. The receiver is interpreted as having 2's-complement representation.
Essential. See Object documentation whatIsAPrimitive."
<primitive: 17>
+ self = 0 ifTrue: [^self].
+ self > 0 ifTrue: [^ super bitShift: arg].
- self >= 0 ifTrue: [^ super bitShift: arg].
^ arg >= 0
ifTrue: [(self negated bitShift: arg) negated]
ifFalse: [(self bitInvert bitShift: arg) bitInvert]!
Nicolas Cellier uploaded a new version of Kernel to project The Trunk:
http://source.squeak.org/trunk/Kernel-cmm.1228.mcz
==================== Summary ====================
Name: Kernel-cmm.1228
Author: cmm
Time: 7 May 2019, 6:36:01.955169 pm
UUID: 2fad2a41-3aec-4e22-b9e8-cce50f7f6808
Ancestors: Kernel-nice.1227
Allow identification of instances of Boolean via #isBoolean.
=============== Diff against Kernel-nice.1227 ===============
Item was added:
+ ----- Method: Boolean>>isBoolean (in category 'testing') -----
+ isBoolean
+ ^ true!
Item was added:
+ ----- Method: Object>>isBoolean (in category 'testing') -----
+ isBoolean
+ ^ false!
Nicolas Cellier uploaded a new version of Tools to project The Trunk:
http://source.squeak.org/trunk/Tools-nice.847.mcz
==================== Summary ====================
Name: Tools-nice.847
Author: nice
Time: 7 May 2019, 9:38:06.649253 am
UUID: 58b94b2d-3cc1-42fc-ace2-c702f38295c8
Ancestors: Tools-dtl.846
Don't propose addLast:times: in MethodFinder, it's been deprecated
=============== Diff against Tools-dtl.846 ===============
Item was changed:
----- Method: MethodFinder>>initialize2 (in category 'initialize') -----
(excessive size, no diff calculated)
Nicolas Cellier uploaded a new version of 60Deprecated to project The Trunk:
http://source.squeak.org/trunk/60Deprecated-nice.34.mcz
==================== Summary ====================
Name: 60Deprecated-nice.34
Author: nice
Time: 7 May 2019, 9:26:52.899828 am
UUID: 882e9027-6b0f-4ef4-9ab6-02e2dff2df3b
Ancestors: 60Deprecated-tpr.33
Deprecate RunArray>>addLast:times:
Companion change to Collections-nice.830/Collections-nice.499
=============== Diff against 60Deprecated-tpr.33 ===============
Item was added:
+ ----- Method: RunArray>>addLast:times: (in category '*60Deprecated') -----
+ addLast: value times: times
+ "Add value as the last element of the receiver, the given number of times"
+ self deprecated: 'use add:withOccurrences:'.
+ ^self add: value withOccurrences: times!