Let's take the inheritance issue first. Yes, Collection has some subclasses where #average makes no sense, such as String. If any subclass of Collection should have #average, it is Array, as #(1 2 3 4) average makes perfect sense. BUT #($a $b $c $d) average makes exactly as much sense as 'abcd' average. So we have - subclasses where a method never makes sense (String) - subclasses where a method always makes sense (ByteArray) - subclasses where a method may or may not make sense (Array). Traits will not help at all with the third category. Historic Smalltalk practice has been to define methods like String>>average self shouldNotImplement. to "cancel" inappropriate methods to deal with the "never" subclasses, but that still does not help with the "maybe" ones.
In my own code I try very hard to ensure that a method is available in a class if and only if the class can have instances where the method makes sense. That is, I try to make sure that #respondsTo: is "honest". It is not always practical. This is not a problem that is peculiar to Smalltalk. Java and C# and C++ and you-name-it also have the "maybe" problem, where a method seems to be available for an object but thanks to its state it is not. As long as sending a message to an inappropriate object (whether due to its class or its state) results in *some* exception, do we really have a problem? 'abcd' average 'abcd' asArray average result in the same error. Now for the roundoff error issue. Oh dear, we really need to do a much better job educating programmers about floating point, we really do. In real number arithmetic, (a + b) - a = b is always true. In floating-point arithmetic it is not. This is easiest to see in cases like (1.0e20 + 1.0) - 1.0e20 where Pharo answers 0.0 instead of 1.0. Less extreme cases still give you roundoff error. Much has been written about how to stably update mean, variance, &c. The simplest thing is to use Welford's algorithm for the weighted mean, using weight +1 to add the new element and -1 to remove the old. On Thu, 9 Apr 2020 at 19:33, Christian Haider < christian.hai...@smalltalked-visuals.com> wrote: > I don’t see how rounding errors could accumulate, if you keep the sum and > not the average. > > The rounding errors should be neutral, because each element is added once > and subtracted once. > > If + and – is symmetrical in this respect, rounding inaccuracies should > balance out. > > > > Cheers, > > Christian > > > > *Von:* Pharo-users <pharo-users-boun...@lists.pharo.org> *Im Auftrag von > *Richard > O'Keefe > *Gesendet:* Donnerstag, 9. April 2020 05:26 > *An:* Any question about pharo is welcome <pharo-users@lists.pharo.org> > *Betreff:* Re: [Pharo-users] Moving/rolling average implementations ? > > > > I note that "self species ofSize: n" is not generally a good idea. > > Consider ByteArray, ShortIntegerArray, WordArray. > > Computing rolling means of these is perfectly sensible, > > but the results will not fit into an array of the same species. > > I'd stick with Array. > > > > The suggestion about subtracting an old element and adding a new > > one is great for integers, but for floating-point numbers risks > > accumulating errors. > > > > The > > > > On Wed, 8 Apr 2020 at 20:07, Cédrick Béler <cdric...@gmail.com> wrote: > > Hi, > > > > I wanted to do a moving/rolling average on raw data [1]. > > I haven’t find code for that (maybe this is done in polymath though). > > > > So I ended writing that (I thing this is SMA): > > > > SequenceableCollection>>movingAverage: anOrder > "Answer the moving or rolling average for anOrder window" > > > > | retval size x y | > > anOrder <= 0 ifTrue: [ Error signal: 'the order must be positive']. > > size := self size - anOrder. > > size negative ifTrue: [ Error signal: 'the collection size is too > small']. > > retval := self species ofSize: size + 1. > > > > x := 1. > > y := anOrder. > > [y <= self size ] whileTrue: [ > > retval at: x put: (self copyFrom: x to: y) average > > x := x + 1. y := y + 1 > > ]. > > ^retval > > > > Not perfect but seems to works quite well (that’s probably better to > remove copyFrom: and use some kind of buffer instead). > > > > Any interest in that ? If any existing code too, I’ll be interested > especially for other implementation (weighted, exponential) ? > > > > > > (#(118 113 105 105 103 99 98 101 100 107) movingAverage: 3) collect: [:v | > v asScaledDecimal: 1 ] . > > > > "an Array(112.0s1 107.7s1 104.3s1 102.3s1 100.0s1 99.3s1 99.7s1 102.7s1)" > > > > Cheers, > > Cédrick > > > > > > > > [1] > https://www.meilleursbrokers.com/techniques-de-trading/moyennes-mobiles.html > (in > French but is understandable) > > > >