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)
>
>
>
>

Reply via email to