[squeak-dev] The Inbox: Kernel-fn.1151.mcz

Levente Uzonyi leves at caesar.elte.hu
Thu Mar 22 00:15:39 UTC 2018


On Wed, 21 Mar 2018, Eliot Miranda wrote:

> 
> 
> On Wed, Mar 21, 2018 at 2:48 PM, Levente Uzonyi <leves at caesar.elte.hu> wrote:
>       On Tue, 20 Mar 2018, Chris Cunningham wrote:
>
>             Hi.  Reopening this thread - probably tomorrow will implement 'better' solution (with documentation).
>
>             On Sat, Feb 10, 2018 at 12:03 PM, Tobias Pape <Das.Linux at gmx.de> wrote:
>
>                   > On 10.02.2018, at 20:36, Tony Garnock-Jones <tonyg at leastfixedpoint.com> wrote:
>                   >
>                   > On 02/10/2018 07:02 PM, Levente Uzonyi wrote:
>                   >> So,
>                   >>    a perform: {#or:. #xor:. #and:} atRandom with: b
>                   >> would just work for that imaginary interpreter if b were a Boolean.
>                   >
>                   > Yes, that "interpreter" works just fine today, if b is a Boolean. It's
>                   > the case where b is a Boolean-producing expression - such as in a "lazy"
>                   > interpreter - that doesn't work without Fabio's proposed change.
>                   >
>                   > I went and looked at the ANSI standard (draft), btw [1].
>                   >
>                   > There, #xor: is specified as taking only a boolean.
>                   >
>                   > So this would be an extension, potentially affecting portability, for
>                   > what that's worth these days.
>                   >
>                   > I think the performance objection has been well-refuted, and I see the
>                   > consistency benefit as being real, but probably pretty limited, and I
>                   > kind of don't like the potential portability implications.
>
>                   I presume the main "feeling" here is parallelity:
>
>                   #& takes an evaluated boolean   #and: takes an unevaluated block
>                   #| takes an evaluated boolean   #or: takes an unevaluated block
>
>                   #xor: takes an evaluated boolean but looks like #and: and #or:,
>                   So it seems to belong to the right side, and then we think again about
>                   the left side, come up with symbols, only to find that #~= and #~~ are already there.
>
>                   So, just lets go all the way and document #xor: better, not making take it a block,
>                   maybe pointing out that #~= ist typically better fitted…
>
>                   Best regards
>                           -Tobias
> 
>
>             So, I have written some tests for speed and 'ensuring the arguments are booleans', with another proposed solution.
>
>             First, speed:
>
>             #xor: base
>             #~= is 124% slower (or 2-1/4 as much time as existing xor: method)
>             #~~ is 75% faster
>             #cbcXor: is 32% slower
>
>             Note: for real speed, use ~~ , not ~= !
>
>             Why cbcXor: ?  It is the only one that makes sure the arguments are boolean - fails otherwise.
> 
> 
> Here is a simpler and faster alternative:
> 
> True >> #xor: aBoolean
> 
>         aBoolean ifTrue: [ ^false ] ifFalse: [ ^true ]
> 
> False >> #xor: aBoolean
> 
>         aBoolean ifTrue: [ ^true ] ifFalse: [ ^false ]
> 
> 
> and is this noticeably slower?
> 
>  True >> #xor: aBoolean
> 
>         ^aBoolean ifTrue: [ false ] ifFalse: [ true ]
> 
> False >> #xor: aBoolean
> 
>         ^aBoolean ifTrue: [ true ] ifFalse: [ false ]

Yes, it is. Here are the bytecodes for your suggestion:

33 <10> pushTemp: 0
34 <99> jumpFalse: 37
35 <71> pushConstant: true
36 <90> jumpTo: 38
37 <72> pushConstant: false
38 <7C> returnTop

And for my variant:

33 <10> pushTemp: 0
34 <98> jumpFalse: 36
35 <79> return: true
36 <7A> return: false

I measured the latter to be 14% faster.

Levente

> 
> but I would much prefer to see either
> 
> Boolean>>xor: aBooleanOrBlock
> 
>     ^ aBooleanOrBlock value not
> 
> or
> 
> True >> #xor: aBooleanOrBlock
> 
>         ^aBooleanOrBlock value ifTrue: [ false ] ifFalse: [ true ]
> 
> False >> #xor: aBooleanOrBlock
> 
>         ^aBooleanOrBlock value ifTrue: [ true ] ifFalse: [ false ]
> 
> The lack of symmetry with and: and or: is, IMO, bad.
> 
>
>       Levente
> 
>
>             Tests to run:
>
>             First, install
>
>             True>>cbcXor: boolean
>             ^boolean isFalse
>             True>>isTrue
>             ^true
>             True>>isFalse
>             ^false
>             False>>cbcXor: boolean
>             ^boolean isTrue
>             False>>isFalse
>             ^true
>             False>>isTrue
>             ^false
>
>             "Setup"
>             pairs := #( true false true true false false false true ).
>             invalidPairs := { true. 1. true. #[ 1 3 0 9 ]. true. 'abc'. false. 1. false. #[ 1 3 0 9 ]. false. 'abc'. 'abc'. true. #[ 1 3 0 9 ]. false. }.
>             methods := {
>             [:f :s| ]. 
>             [:f :s| f xor: s]. 
>             [:f :s| f cbcXor: s]. 
>             [:f :s| f ~= s]. 
>             [:f :s| f ~~ s].
>             }.
>             "Validity Test"
>             validCheck := methods collect: [:m|
>>             m sourceString. 
>             #( true false false true ) = (pairs pairsCollect: [:a :b| [m value: a value: b] on: Error do: [#error]])
>             ifTrue: ['Valid'] ifFalse: ['ERRORS'].
>             pairs pairsCollect: [:a :b| [m value: a value: b] on: Error do: [#error]]. 
>             }].
>             "all methods are valid"
>             "Testing that non-booleans actually result in errors, and not false positive/negatives"
>             invalidCheck := methods collect: [:m|
>>             m sourceString. 
>             ((invalidPairs pairsCollect: [:a :b| [m value: a value: b] on: Error do: [#error]]) select: [:r| r = #error]) size = 8
>             ifTrue: ['Valid'] ifFalse: ['ERRORS'].
>             invalidPairs pairsCollect: [:a :b| [m value: a value: b] on: Error do: [#error]]. 
>             }].
>             "Only #cbcXor: correctly fails all of these.  Some interesting results..."
>             "Timing test.  Need to run 10,000,000 to get reasonable distinctions on my machine."
>             timing := methods collect: [:m|
>             { m sourceString.  [[10000000 timesRepeat: [pairs pairsDo: m]] timeToRun] on: Error do: [#invalid]. }
>             ].
>             "And showing percentage slower"
>             base := timing first second.
>             bench := timing second second - base.
>             timing allButFirst collect: [:res| { res first. this := res second - base. ((this - bench) * 100 / bench) rounded. }].
>
>             Thanks,
>             cbc
> 
> 
> 
> 
> 
> 
> 
> --
> _,,,^..^,,,_
> best, Eliot
> 
>


More information about the Squeak-dev mailing list