İki sayının ortalamasını hesapla


41

feragatname: Ortalama ortalaması benim tarafımdan yapılmıştır.

sayılarının aritmetik ortalamasını tanımlayın, sayılarının geometrik ortalamasını sayıların harmonik ortalamasını olarak tanımlayın sayısının ikinci dereceden ortalamasını olarak Ortalama ortalama ( ) aşağıdaki gibi tanımlanır: Dört diziyi ( ) aşağıdaki gibi tanımlayın .n

M1(x1,...,xn)=x1+x2+...+xnn
n
M0(x1,...,xn)=x1x2...xnn
n
M1(x1,...,xn)=n1x2+1x2+...+1xn
n
M2(x1,...,xn)=x12+x22+...+xn2n
MMak,bk,ck,dk
a0=M1(x1,...,xn),b0=M0(x1,...,xn),c0=M1(x1,...,xn),d0=M2(x1,...,xn),ak+1=M1(ak,bk,ck,dk),bk+1=M0(ak,bk,ck,dk),ck+1=M1(ak,bk,ck,dk),dk+1=M2(ak,bk,ck,dk)
Dört sekansın tümü bir araya gelir Aynı sayı, , .MM(x1,x2,...,xn)

Örnek

1 ve 2'nin ortalama ortalaması şu şekilde hesaplanır: Sonra Dizilerin daha sonraki hesaplamaları açık olmalıdır. Aynı sayıya yaklaştıkları , yaklaşık .

a0=(1+2)/2=1.5,b0=12=21.4142,c0=211+12=431.3333,d0=12+222=521.5811.
a1=1.5+1.4142+1.3333+1.581141.4571,b1=1.51.41421.33331.581141.4542,c1=411.5+11.4142+11.3333+11.58111.4512,d1=1.52+1.41422+1.33332+1.5811241.4601.
1.45568889

Meydan okuma

İki pozitif gerçek sayı verildiğinde, ve ( ), Ortalama ortalama hesaplayın .aba<bMM(a,b)

Test durumları

1 1 => 1
1 2 => 1.45568889
100 200 => 145.568889
2.71 3.14 => 2.92103713
0.57 1.78 => 1.0848205
1.61 2.41 => 1.98965438
0.01 100 => 6.7483058

notlar

  • Çıktı ile doğru çıktı arasındaki fark, giriş sayıları arasındaki farkın mutlak değerinin 1 / 100000'inden büyük değilse, programınız geçerlidir.
  • Çıktı tek bir sayı olmalıdır.

Bu , yani en kısa kod kazanır!




11
Ne kadar hassas olmamız gerekiyor?
Ignorance'ın Davranışı


1
İlk testin tüm test durumlarınızda olduğu gibi her zaman saniyeden küçük olduğunu varsayabilir miyiz? (Değilse Java cevabımı geri
alırım

Yanıtlar:


14

Wolfram Dili (Mathematica) , 52 bayt

#//.x_:>N@{M@x,E^M@Log@x,1/M[1/x],M[x^2]^.5}&
M=Mean

Çevrimiçi deneyin!

İlk yaklaşımımda, bu yerleşikleri kullandım
Mean GeometricMean HarmonicMeanveRootMeanSquare

Baytları kaydetmek için bazı ikameler

HarmonicMean-> 1/Mean[1/x] @Robin Ryder (3 bayt kaydedildi)
GeometricMean-> E^Mean@Log@x@A tarafından. Rex (2 bayt kaydedildi)
RootMeanSquare-> Mean[x^2]^.5@A. Rex (4 bayt kaydedildi)

nihayet atayabilir Meaniçin M(@ovs önerdiği gibi) ve 5 daha bayt tasarruf


GeometricMean
Robin Ryder

@RobinRyder Harmonik demek istediğine inanıyorum .. güzel!
J42161217

1
8 bayttan daha fazla tasarruf edin :#//.x_:>N@{Mean@x,E^Mean@Log@x,1/Mean[1/x],Mean[x^2]^.5}&
A. Rex

@ovs ..... düzenlendi
J42161217

10

R, 70 69 67 bayt

x=scan();`?`=mean;while(x-?x)x=c((?x^2)^.5,?x,2^?log2(x),1/?1/x);?x

Çevrimiçi deneyin!

Daha iyi şartlandırma ile -1 bayt.
Üs 2'ye geçerek -2 bayt.

Diğer bazı cevaplar gibi, bu da geometrik ortalamanın ifadesini log ölçeğinde aritmetik bir ortalama olarak kullanır (burada temel 2'de):

M0(x1,,xn)=2M1(log2x1,,log2xn).

Ayrıca kullandığı gerçeğini o , yani . Durum nedenle eşdeğerdir , fırsat varken döngüsünde kullanılacak budur; bu, koşul bir vektör olduğunda sadece ilk elemanı dikkate alan sözdizimini kötüye kullanmak , böylece araçların depolanma sırasını kötüye kullanmakla başarılır . (Not biz de kullanabileceği o dört minimum yerine beri, ama biz kullanamadı veya durumda.)k,dkakbkckdk=max(ak,bk,ck,dk)ak=bk=ck=dkdk=M1(ak,bk,ck,dk)whileckakbk

While döngüsünden çıktığımızda, xsabit bir vektördür. Nihai ?xbir sayısal bunu azaltma ortalama hesaplar.


1
yerine olmamalı mı ? l O g x nlnxnlogxn
Tau

@Tau Evet, doğal logaritmayı ifade ettim, R varsayılanı. Her neyse, şimdi bunu 2 bayt için 2 logaritma olarak değiştirdim. log
Robin Ryder

6

J , 34 bayt

(Değişkene atama olmadan bir ifade olarak 31 f)

f=:1{(^.z,%z,*:z,[z=:(+/%#)&.:)^:_

Çevrimiçi deneyin!

İşlevler için ave b, a &.: b( "Bir b altında" ( zorluğun )) eşdeğerdir (b inv) a bsonra ters b, b, o zaman geçerlidir -. Bu durumda, geometrik / harmonik / karesel ortalama, sırasıyla "altında" logaritma, ters çevirme ve kare olan aritmetik ortalamadır.


5

TI-BASIC, 42 35 34 bayt

@SolomonUcko sayesinde -1 bayt

While max(ΔList(Ans:{mean(Ans),√(mean(Ans²)),mean(Ans^-1)^-1,e^(mean(ln(Ans:End:Ans(1

Giriş, içindeki iki tamsayının listesidir Ans. Program tamamlandığında
çıktı kaydedilir Ansve otomatik olarak yazdırılır.

Geometrik harmonik ve ikinci dereceden aracı için kullanılan formüller kapalı dayanır user202729 açıklamasının .

Örnek:

{1,2
           {1 2}
prgmCDGFB
     1.455688891
{100,200
       {100 200}
prgmCDGFB
     145.5688891

Açıklama:
(yeni satırlar açıklama eklenmiştir Onlar yoktur. DEĞİL kodu görüntülenir.)

While max(ΔList(Ans           ;loop until all elements of the current list are equal
                              ; the maximum of the change in each element will be 0
{                             ;create a list containing...
 mean(Ans),                   ; the arithmetic mean
 √(mean(Ans²)),               ; the quadratic mean
 mean(Ans^-1)^-1,             ; the harmonic mean
 e^(mean(ln(Ans               ; and the geometric mean
End
Ans(1                         ;keep the first element in "Ans" and implicitly print it

Notlar:

TI-BASIC belirtilmiş bir dildir. Karakter sayısı bayt sayısına eşit değil .

e^(olan bu bir baytlık belirteci.

^-1bu bir baytlık belirteç için kullanılır .
Bunun ^-1yerine yazıyı seçtim çünkü belirteç ֿ¹kod bloğundayken benziyor .

√(olan bu bir baytlık belirteci.

ΔList(olan bu iki baytlık belirteci.


Bence geometrik ortalamayı son koyarak parantezi kurtarabilirsin.
Solomon Ucko

@SolomonUcko ah, fark ettiğiniz için teşekkürler! Bunu daha önce düşünmedim.
Tau

max(DeltaList(Ans-> variance(Ans.
lirtosiast

5

Java 10, 234 229 214 211 215 206 203 196 180 177 bayt

a->{for(;a[1]-a[0]>4e-9;){double l=a.length,A[]={0,0,0,1};for(var d:a){A[2]+=d/l;A[3]*=Math.pow(d,1/l);A[0]+=1/d;A[1]+=d*d;}A[0]=l/A[0];A[1]=Math.sqrt(A[1]/l);a=A;}return a[0];}

@PeterCordes sayesinde -5 bayt . @ RobinRyder'in R cevabından ilham alan @PeterCordes
sayesinde -15 bayt daha . +4 bayt çünkü girişlerin ön sipariş verildiğini varsaydım. @ OlivierGrégoire sayesinde -27 bayt .

Çevrimiçi deneyin.

Açıklama:

a->{                        // Method with double-array parameter and double return-type
  for(;a[1]-a[0]            //  Loop as long as the difference between the 2nd and 1st items
                >4e-9;){    //  is larger than 0.000000004:
    double l=a.length,      //   Set `l` to the amount of values in the array `a`
           A[]={0,0,0,1};   //   Create an array `A`, filled with the values [0,0,0,1]
    for(var d:a){           //   Inner loop over the values of `a`:
      A[2]+=d/l;            //    Calculate the sum divided by the length in the third spot
      A[3]*=Math.pow(d,1/l);//    The product of the power of 1/length in the fourth spot
      A[0]+=1/d;            //    The sum of 1/value in the first spot
      A[1]+=d*d;            //    And the sum of squares in the second spot
    }                       //   After the inner loop:
                            //   (the third spot of the array now holds the Arithmetic Mean)
                            //   (the fourth spot of the array now holds the Geometric Mean)
    A[0]=l/A[0];            //   Divide the length by the first spot
                            //   (this first spot of the array now holds the Harmonic Mean)
    A[1]=Math.sqrt(A[1]/l); //   Take the square of the second spot divided by the length
                            //   (this second spot of the array now holds the Quadratic Mean)
    a=A;                    //   And then replace input `a` with array `A`
  }                         //  After the outer loop when all values are approximately equal:
  return a[0];}             //  Return the value in the first spot as result

C'de f+=Math.abs(d-D)<1e-9;bir boolean karşılaştırma sonucundan örtük dönüşüm elde edersiniz ve 0/1 tamsayısına ve sonra double. Java'nın bunun için küçük bir sözdizimi var mı? Yoksa mutlak farklılıkların toplamının yeterince küçük olup f+=Math.abs(d-D)olmadığını kontrol etmek mümkün mü?
Peter Cordes

1
Evet, test durumlarınız için, f>1e-8bir döngü koşulu olarak çalışır: 229 bayt. a->{for(double f=1,D,A[],l;f>1e-8;a=A){D=a[0];A=new double[]{f=0,1,0,0};for(var d:a){f+=Math.abs(d-D);A[0]+=d;A[1]*=d;A[2]+=1/d;A[3]+=d*d;}A[0]/=l=a.length;A[1]=Math.pow(A[1],1/l);A[2]=l/A[2];A[3]=Math.sqrt(A[3]/l);}return a[0];}. Bununla birlikte 1e-9, daha yavaş çalışır (yaklaşık iki kat CPU zamanı), aslında 4 kat daha d-Dküçük olması için daha fazla yineleme yapmak zorunda kalır . İle 1e-7, 1e-8 ile aynı hızda. İle 1e-6, sondaki bazı basamaklar bir durum için farklılık gösterir.
Peter Cordes

1
@ RobinRyder'ın cevabı, ikinci dereceden ortalamanın her zaman en büyük ve harmonik her zaman en küçük olduğuna işaret eder, bu nedenle belki de ftamamen hendek kazıp kontrol edebilirsiniz a[3]-a[2]<4e-9.
Peter Cordes

1
@PeterCordes l==2||yani (golf l<3|) demek . Ama evet, iyi nokta; Ekledim. :)
Kevin Cruijssen

2
Toplayıcı indirgeyicileri toplayarak 180 bayt .
Olivier Grégoire

3

Kömür , 40 bayt

W‹⌊θ⌈θ≔⟦∕ΣθLθXΠθ∕¹Lθ∕LθΣ∕¹θ₂∕ΣXθ²Lθ⟧θI⊟θ

Çevrimiçi deneyin! Bağlantı, kodun ayrıntılı bir versiyonudur. Girdiyi bir sayı dizisi olarak alır. Açıklama:

W‹⌊θ⌈θ

Dizi farklı değerler içeriyorsa tekrarlayın ...

≔⟦....⟧θ

... diziyi bir değerler listesi ile değiştirin:

∕ΣθLθ

... Ortalama...

XΠθ∕¹Lθ

... geometrik ortalama ...

∕LθΣ∕¹θ

... harmonik demek ...

₂∕ΣXθ²Lθ

... ve kök ortalama kare.

I⊟θ

Dizinin bir öğesini dizeye dönüştürmek ve örtük olarak yazdırmak.




3

05AB1E , 26 24 23 bayt

Δ©ÅA®.²ÅAo®zÅAz®nÅAt)}н

Çevrimiçi deneyin veya tüm test senaryolarının adımlarını görün .

@Grimy sayesinde -1 bayt .

Geometrik ortalama için 23 byter alternatif:

Δ©P®gzm®ÅA®zÅAz®nÅAt)}н

Çevrimiçi deneyin veya tüm test senaryolarının adımlarını görün .

Açıklama:

Δ         # Loop until the list no longer changes:
 ©        #  Store the current list in variable `®` (without popping)
          #  (which is the implicit input-list in the first iteration)
          #  Arithmetic mean:
  ÅA      #   Builtin to calculate the arithmetic mean of the list
          #  Geometric mean:
  ®.²     #   Take the base-2 logarithm of each value in the list `®`
     ÅA   #   Get the arithmetic mean of that list
       o  #   And take 2 to the power of this mean
          #  Harmonic mean:
  ®z      #   Get 1/x for each value x in the list `®`
    ÅA    #   Get the arithmetic mean of that list
      z   #   And calculate 1/y for this mean y
          #  Quadratic mean:
  ®n      #   Take the square of each number x in the list from the register
    ÅA    #   Calculate the arithmetic mean of this list
      t   #   And take the square-root of that mean
  )       #  Wrap all four results into a list
        # After the list no longer changes: pop and push its first value
          # (which is output implicitly as result)

23:Δ©P®gzm®ÅA®zÅAz®nÅAt)}н
Grimmy

@Grimy Teşekkürler! Y2/4 yerine uzunluğu kullanmayı düşünmediğime inanamıyorum . :)
Kevin Cruijssen

1
Başka bir 23 bu betters gösterir diğerleri için geometrik ortalama benzerlik: Δ©ÅA®.²ÅAo®zÅAz®nÅAt)}н. Maalesef, bütün bunları yeniden canlandırabiliriz gibi görünmüyor ÅA.
Grimmy

@Grimy Oh, bu ikinci versiyonu beğendim. :) EDIT: Oops .. açıklamadaki yanlışlığımı fark ettiğiniz için teşekkür ederiz ..>.>
Kevin Cruijssen

05ab1e de çok iyi programlamıyorum, fakat toplamları hesaplayabilir ve daha sonra hepsini uzunluğa bölebilir misiniz?
birisi

2

Jöle , 25 24 bayt

Wẋ4¹ÆlÆeƭ²½ƭİ4ƭÆm$€⁺µÐLḢ

Çevrimiçi deneyin!

açıklama

                    µÐL | Repeat until unchanged:
W                       |   Wrap as a list
 ẋ4                     |   Copy list 4 times
                   ⁺    |   Do twice:
                 $€     |     For each copy of the list:
             4ƭ         |     One of these functions, cycling between them:
   ¹                    |       Identity
    ÆlÆeƭ               |       Alternate between log and exp
         ²½ƭ            |       Alternate between square and square root
            İ           |       Reciprocal
               Æm       |    Then take the mean
                       Ḣ| Finally take the first item

Jelly'de oldukça kötüyüm ama P*İLgeometrik anlam için çalışmaya benzer bir şey olabilir mi?
biri

Bazılarında olması gerekecek, P*Lİ$yani baytları kurtarmaz. Bu, Æmbaytlara mal olmadan bir çizgiyi geri getirebileceğim anlamına gelirdi , ancak her birinin şu anda özünde aritmetik bir ortalamaya sahip olması gerçeğini oldukça seviyorum.
Nick Kennedy,

2

Python 3 , 152 bayt

from math import*
s=sum
def f(*a):l=len(a);return 2>len({*a})and{*a}or f(s(a)/l,l/s(map(pow,a,l*[-1])),exp(s(map(log,a))/l),(s(map(pow,a,l*[2]))/l)**.5)

Çevrimiçi deneyin!

Özyinelemeli işlevi f, kayan nokta hassasiyetine yakınlaşacaktır. Her ölçekteki pozitif sayıların tüm listeleri için prensip olarak çalışır , ancak Python'un özyineleme sınırlaması ile sınırlıdır , bazı test durumlarında yuvarlama hatası.


Alternatif olarak, 9 ondalık hassasiyet için çözüm:

Python 3 , 169 bayt

from math import*
s=sum
def f(*a):l=len(a);return(2>len({round(i,9)for i in a}))*a[0]or f(s(a)/l,l/s(map(pow,a,l*[-1])),exp(s(map(log,a))/l),(s(map(pow,a,l*[2]))/l)**.5)

Çevrimiçi deneyin!


1

C # , 173 bayt

double m(int n,params double[]a)=>(n<1?a[0]:m(n-1,a.Sum()/a.Length,Math.Pow(a.Aggregate((t,x)=>t*x),1.0/a.Length),a.Length/a.Sum(x=>1/x),Math.Sqrt(a.Sum(x=>x*x)/a.Length)));

Çevrimiçi deneyin!


2
Bu gerçekten geçirilmesi gereken bir değişkene benziyor. Ayrıca, eklemek zorunda using Systemve using System.Linqonlar çalıştırmak için program için gerekli olduğundan, sizin bayt sayısında. Derleyicinizi, bu içe aktarmalara ihtiyaç duymayan C # Visual Interactive Compiler olarak değiştirebilirsiniz. Ayrıca, 1.0->1d
Cehalet uygulaması

1

Temiz , 124 bayt

import StdEnv
f=avg o limit o iterate\l=let n=toReal(length l)in[avg l,prod l^(1.0/n),n/sum[1.0/x\\x<-l],avg[x*x\\x<-l]^0.5]

Çevrimiçi deneyin!

İşlem, sonuç değişmeyi bırakana kadar gerçekleştirir.

Sınırlı hassas kayan nokta için hurra!


1

Pyth, 32 bayt

h.Wt{H[.OZ@*FZJlZcJscL1Z@.O^R2Z2

Online Deneyin burada ya bir kerede tüm test durumları (aşağıdaki nota bakın, iki bar) doğrulamak burada . Girişi liste olarak kabul eder.

Yuvarlama ile ilgili bazı sorunlar var gibi görünmektedir, çünkü bazı girdiler aksi durumda olması gerektiği zaman doğru şekilde birleşmemektedir. Özellikle, test durumu 0.01 100değerlerde sıkışır [6.748305820749738, 6.748305820749738, 6.748305820749739, 6.748305820749738]ve test durumu 1.61 2.41sıkışır [1.9896543776640825, 1.9896543776640825, 1.9896543776640827, 1.9896543776640825]- her iki durumda da 3. ortalamanın (harmonik ortalamanın) diğerlerinden farklı olduğunu unutmayın.

Bu sorunun girişimi geçersiz kıldığından emin değilim, ancak çalışması gerektiği şekilde yine de gönderiyorum . Eğer bu kabul edilebilir değilse, bu test takımında görüldüğü gibi, her bir aracın 10 ondalık basamağa yuvarlanması için .RRTönce iç kısma sabitlenebilir .[

h.Wt{H[.OZ@*FZJlZcJscL1Z@.O^R2Z2)Q   Implicit: Q=eval(input())
                                     Trailing )Q inferred
 .W                              Q   Funcitonal while: While condition is true, call inner. Starting value Q
   t{H                               Condition function: current input H
    {H                                 Deduplicate H
   t                                   Discard first value
                                         Empty list is falsey, so while is terminated when means converge
      [.OZ@*FZJlZcJscL1Z@.O^R2Z2)    Inner function: current input Z
              JlZ                      Take length of Z, store in J
       .OZ                             (1) Arithmetic mean of Z
           *FZ                         Product of Z
          @   J                        (2) Jth root of the above
                     L Z               Map each element of Z...
                    c 1                ... to its reciprocal
                   s                   Sum the above
                 cJ                    (3) J / the above
                            R Z        Map each element of Z...
                           ^ 2         ... to its square
                         .O            Arithmetic mean of the above
                        @      2       (4) Square root of the above
      [                         )      Wrap results (1), (2), (3), and (4) in a list
                                         This is used as the input for the next iteration of the loop
h                                    Take the first element of the result, implicit print

Ben çok emin tekrarlanan hesaplama önceki değerlerine etrafında atlamak olmaz ediyorum olduğundan, yerini alabilecek .Wt{Hile uiçin -4 bayt (ve değişim Ziçin G)
ar4093

1

Japt v2.0a0 -g, 42 38 bayt

â ÊÉ?ß[Ux²÷(V=UÊ)¬Ux÷V U×qV V÷Ux!÷1]:U

Daha kısa bir yol olmalı ... Bu bir canavarlık! @Shaggy sayesinde 4 bayt kaydedildi!

Dene


38 bayt . Ama katılıyorum, daha kısa bir yol olmalı!
Shaggy,

1

C # (Visual C # Etkileşimli Derleyici) , 177 bayt

double f(double[]g)=>g.All(c=>Math.Abs(c-g[0])<1e-9)?g[0]:f(new[]{g.Sum()/(z=g.Length),Math.Pow(g.Aggregate((a,b)=>a*b),1d/z),z/g.Sum(x=>1/x),Math.Sqrt(g.Sum(x=>x*x)/z)});int z;

@KevinCruijjsen'e, kayan nokta hassasiyetinin kullanılmasının sorunlara yol açtığını gösterdiği için teşekkürler! Çiftler tam olarak kusursuz olsaydı 163 bayt olurdu.

Çevrimiçi deneyin!


Son iki test durumu StackOverflowExceptionkayan nokta hassasiyetinden kaynaklanmaktadır. c==g[0]Senin yerine bir şey yapabilirdin Math.Abs(c-g[0])<1e-9. Çevrimiçi deneyin.
Kevin Cruijssen

@KevinCruijssen Teşekkürler, kayan nokta sayılarıyla uğraşan böyle bir acı
Ignorance uygulaması

1

x86 makine kodu (128-bit SSE1 ve AVX kullanarak SIMD 4x float) 94 bayt

x86 makine kodu (SIMD 4x 256-bit AVX kullanarak çift) 123 bayt

floatsöz konusu test vakalarını geçiyor, ancak bunun gerçekleşmesi için yeterince küçük bir döngü-çıkış eşiğiyle, rastgele girdilerle sonsuz bir döngüye sıkışması kolay.

Paketlenmiş tek duyarlıklı SSE1 yönergeleri 3 bayt, ancak SSE2 ve basit AVX komutları 4 bayttır. (Skaler tekli komutlar sqrtssda 4 bayt uzunluğundadır, bu yüzden sqrtpssadece düşük elementi önemsememe rağmen kullanıyorum. Modern donanımdaki sql'lerden bile daha yavaş değil). 2 bayt ve movaps + op kaydetmek için tahribatsız hedef için AVX kullandım.
İkili sürümde movlhps64 bit parçalarını kopyalamak için hala bir çift yapabiliriz (çünkü genellikle yatay toplamın düşük elemanını önemseriz). 256 bitlik bir SIMD vektörünün yatay toplamı vextractf128, yüksek yarı elde etmek için fazladan bir değer gerektirir , buna karşılık float için yavaş ama küçük 2x haddpsstratejisi vardır . doublesürümde ayrıca 2x 4 bayt yerine 2x 8 bayt sabit gerekir. Genel olarak floatsürümün 4 / 3'üne yakın bir boyutta ortaya çıkıyor .

mean(a,b) = mean(a,a,b,b)Bu araçların 4 tanesi için, bu nedenle girişi 4 öğeye kadar kopyalayabiliriz ve asla uzunluk = 2 uygulamak zorunda kalmayız. Bu nedenle, örneğin geometrik ortalamaları 4. kök = sqrt (sqrt) olarak kodlayabiliriz. Ve sadece bir FP sabitine ihtiyacımız var 4.0.

4'ün hepsinde tek bir SIMD vektörümüz var [a_i, b_i, c_i, d_i]. Bundan sonra, 4 aracı ayrı kayıtlardaki skaler olarak hesaplıyoruz ve bir sonraki yineleme için tekrar karıştırıyoruz. (SIMD vektörleri üzerindeki yatay işlemler elverişli değildir, ancak dengelemek için yeterli durumda 4 öğenin tümü için aynı şeyi yapmamız gerekir. Bunun x87 versiyonunda başladım, ancak çok uzun sürüyordu ve eğlenmiyordu.)

İlmek çıkış koşulu }while(quadratic - harmonic > 4e-5)(veya daha küçük bir sabit double) dayanmaktadır RobinRyder Ar cevap @ ve Kevin Cruijssen Java cevap : kuadratik ortalama her zaman büyük büyüklüğü ve harmonik ortalama daima en küçük (görmezden yuvarlama hataları) 'dir. Böylece yakınsaklığı tespit etmek için bu ikisi arasındaki deltayı kontrol edebiliriz. Aritmetik ortalamayı skaler sonuç olarak döndürürüz. Genellikle bu ikisi arasındadır ve muhtemelen yuvarlama hatalarına en az hassastır.

Float sürümü : float meanmean_float_avx(__m128);xmm0 içindeki arg ve return değerleriyle çağrılabilir. (Yani x86-64 System V veya Windows x64 vectorcall, ancak x64 fastcall değil.) Veya dönüş tipini, __m128test için ikinci dereceden ve harmonik ortalamada alabileceğiniz şekilde ilan edin .

Bunun floatxmm0 ve xmm1'de 2 ayrı argüman almasına izin vermek 1 ekstra bayta mal olacaktır: birlikte karıştırmak ve 2 girişi çoğaltmak için shufpsbir imm8'e (sadece yerine unpcklps xmm0,xmm0) ihtiyaç duyarız .

    40  address                    align 32
    41          code bytes         global meanmean_float_avx
    42                             meanmean_float_avx:
    43 00000000 B9[52000000]           mov      ecx, .arith_mean      ; allows 2-byte call reg, and a base for loading constants
    44 00000005 C4E2791861FC           vbroadcastss  xmm4, [rcx-4]    ; float 4.0
    45                             
    46                                 ;; mean(a,b) = mean(a,b,a,b) for all 4 types of mean
    47                                 ;; so we only ever have to do the length=4 case
    48 0000000B 0F14C0                 unpcklps xmm0,xmm0          ; [b,a] => [b,b,a,a]
    49                             
    50                                 ; do{ ... } while(quadratic - harmonic > threshold);
    51                             .loop:
    52                             ;;; XMM3 = geometric mean: not based on addition.  (Transform to log would be hard.  AVX512ER has exp with 23-bit accuracy, but not log.  vgetexp = floor(lofg2(x)), so that's no good.)
    53                                 ;; sqrt once *first*, making magnitudes closer to 1.0 to reduce rounding error.  Numbers are all positive so this is safe.
    54                                 ;; both sqrts first was better behaved, I think.
    55 0000000E 0F51D8                 sqrtps   xmm3, xmm0                 ; xmm3 = 4th root(x)
    56 00000011 F30F16EB               movshdup xmm5, xmm3                 ; bring odd elements down to even
    57 00000015 0F59EB                 mulps    xmm5, xmm3
    58 00000018 0F12DD                 movhlps  xmm3, xmm5                 ; high half -> low
    59 0000001B 0F59DD                 mulps    xmm3, xmm5                 ; xmm3[0] = hproduct(sqrt(xmm))
    60                             ;    sqrtps   xmm3, xmm3                 ; sqrt(hprod(sqrt)) = 4th root(hprod)
    61                                 ; common final step done after interleaving with quadratic mean
    62                             
    63                             ;;; XMM2 = quadratic mean = max of the means
    64 0000001E C5F859E8               vmulps   xmm5, xmm0,xmm0
    65 00000022 FFD1                   call     rcx                ; arith mean of squares
    66 00000024 0F14EB                 unpcklps xmm5, xmm3         ; [quad^2, geo^2, ?, ?]
    67 00000027 0F51D5                 sqrtps   xmm2, xmm5         ; [quad,   geo,   ?, ?]
    68                             
    69                             ;;; XMM1 = harmonic mean = min of the means
    70 0000002A C5D85EE8               vdivps   xmm5, xmm4, xmm0    ; 4/x
    71 0000002E FFD1                   call     rcx                ; arithmetic mean (under inversion)
    72 00000030 C5D85ECD               vdivps   xmm1, xmm4, xmm5    ; 4/.  (the factor of 4 cancels out)
    73                             
    74                             ;;; XMM5 = arithmetic mean
    75 00000034 0F28E8                 movaps   xmm5, xmm0
    76 00000037 FFD1                   call     rcx
    77                             
    78 00000039 0F14E9                 unpcklps  xmm5, xmm1           ;     [arith, harm, ?,?]
    79 0000003C C5D014C2               vunpcklps xmm0, xmm5,xmm2      ; x = [arith, harm, quad, geo]
    80                             
    81 00000040 0F5CD1                 subps    xmm2, xmm1        ; largest - smallest mean: guaranteed non-negative
    82 00000043 0F2E51F8               ucomiss  xmm2, [rcx-8]     ; quad-harm > convergence_threshold
    83 00000047 73C5                   jae     .loop
    84                             
    85                                 ; return with the arithmetic mean in the low element of xmm0 = scalar return value
    86 00000049 C3                     ret
    87                             
    88                             ;;; "constant pool" between the main function and the helper, like ARM literal pools
    89 0000004A ACC52738           .fpconst_threshold:   dd 4e-5    ; 4.3e-5 is the highest we can go and still pass the main test cases
    90 0000004E 00008040           .fpconst_4:    dd 4.0
    91                             .arith_mean:               ; returns XMM5 = hsum(xmm5)/4.
    92 00000052 C5D37CED               vhaddps   xmm5, xmm5         ; slow but small
    93 00000056 C5D37CED               vhaddps   xmm5, xmm5
    94 0000005A 0F5EEC                 divps     xmm5, xmm4        ; divide before/after summing doesn't matter mathematically or numerically; divisor is a power of 2
    95 0000005D C3                     ret

    96 0000005E 5E000000           .size:      dd $ - meanmean_float_avx
       0x5e = 94 bytes

(İle oluşturulan NASM listesi nasm -felf64 mean-mean.asm -l/dev/stdout | cut -b -34,$((34+6))-. Liste bölümünü soyun ve kaynağı ile kurtarın cut -b 34- > mean-mean.asm)

SIMD yatay toplamı ve 4'e bölünmesi (yani aritmetik ortalama) ayrı bir fonksiyonda call(adresin maliyetini düşürmek için bir fonksiyon işaretçisi ile) uygulanır. İle 4/xdaha önce / sonra veya x^2önce ve sqrt sonra biz harmonik ortalama ve kuadratik ortalama olsun. (Tam olarak gösterilebilir olanla divçarpmak yerine bu talimatları yazmak acı vericiydi 0.25.)

Geometrik ortalama, çarpma ve zincirleme sqrt ile ayrı ayrı uygulanır. Veya üs biriminin büyüklüğünü azaltmak ve belki de sayısal kesinliğe yardımcı olmak için bir sqrt ile. floor(log2(x))İşlem kaydı yalnızca AVX512 üzerinden kullanılamaz vgetexpps/pd. Exp, AVX512ER (yalnızca Xeon Phi) aracılığıyla kullanılabilir, ancak yalnızca 2 ^ -23 hassasiyetle kullanılabilir.

128-bit AVX talimatlarını ve eski SSE'yi karıştırmak performans sorunu değildir. 256-bit AVX'i eski SSE ile karıştırmak Haswell'de olabilir, ancak Skylake'de SSE talimatları için potansiyel olarak yanlış bir bağımlılık yaratıyor. doubleSürümümün gereksiz yere taşınan deprem zincirlerinden ve div / sqrt gecikme / verimdeki tıkanıklıklardan kaçındığını düşünüyorum .

Çift versiyon:

   108                             global meanmean_double_avx
   109                             meanmean_double_avx:
   110 00000080 B9[E8000000]           mov      ecx, .arith_mean
   111 00000085 C4E27D1961F8           vbroadcastsd  ymm4, [rcx-8]    ; float 4.0
   112                             
   113                                 ;; mean(a,b) = mean(a,b,a,b) for all 4 types of mean
   114                                 ;; so we only ever have to do the length=4 case
   115 0000008B C4E37D18C001           vinsertf128   ymm0, ymm0, xmm0, 1       ; [b,a] => [b,a,b,a]
   116                             
   117                             .loop:
   118                             ;;; XMM3 = geometric mean: not based on addition.
   119 00000091 C5FD51D8               vsqrtpd      ymm3, ymm0     ; sqrt first to get magnitude closer to 1.0 for better(?) numerical precision
   120 00000095 C4E37D19DD01           vextractf128 xmm5, ymm3, 1           ; extract high lane
   121 0000009B C5D159EB               vmulpd       xmm5, xmm3
   122 0000009F 0F12DD                 movhlps      xmm3, xmm5              ; extract high half
   123 000000A2 F20F59DD               mulsd        xmm3, xmm5              ; xmm3 = hproduct(sqrt(xmm0))
   124                                ; sqrtsd       xmm3, xmm3             ; xmm3 = 4th root = geomean(xmm0)   ;deferred until quadratic
   125                             
   126                             ;;; XMM2 = quadratic mean = max of the means
   127 000000A6 C5FD59E8               vmulpd   ymm5, ymm0,ymm0
   128 000000AA FFD1                   call     rcx                ; arith mean of squares
   129 000000AC 0F16EB                 movlhps  xmm5, xmm3         ; [quad^2, geo^2]
   130 000000AF 660F51D5               sqrtpd   xmm2, xmm5         ; [quad  , geo]
   131                             
   132                             ;;; XMM1 = harmonic mean = min of the means
   133 000000B3 C5DD5EE8               vdivpd   ymm5, ymm4, ymm0    ; 4/x
   134 000000B7 FFD1                   call     rcx                 ; arithmetic mean under inversion
   135 000000B9 C5DB5ECD               vdivsd   xmm1, xmm4, xmm5    ; 4/.  (the factor of 4 cancels out)
   136                             
   137                             ;;; XMM5 = arithmetic mean
   138 000000BD C5FC28E8               vmovaps  ymm5, ymm0
   139 000000C1 FFD1                   call     rcx
   140                             
   141 000000C3 0F16E9                 movlhps     xmm5, xmm1            ;     [arith, harm]
   142 000000C6 C4E35518C201           vinsertf128 ymm0, ymm5, xmm2, 1   ; x = [arith, harm, quad, geo]
   143                             
   144 000000CC C5EB5CD1               vsubsd   xmm2, xmm1               ; largest - smallest mean: guaranteed non-negative
   145 000000D0 660F2E51F0             ucomisd  xmm2, [rcx-16]           ; quad - harm > threshold
   146 000000D5 77BA                   ja      .loop
   147                             
   148                                 ; vzeroupper ; not needed for correctness, only performance
   149                                 ; return with the arithmetic mean in the low element of xmm0 = scalar return value
   150 000000D7 C3                     ret
   151                             
   152                             ; "literal pool" between the function
   153 000000D8 95D626E80B2E113E   .fpconst_threshold:   dq 1e-9
   154 000000E0 0000000000001040   .fpconst_4:    dq 4.0            ; TODO: golf these zeros?  vpbroadcastb and convert?
   155                             .arith_mean:                     ; returns YMM5 = hsum(ymm5)/4.
   156 000000E8 C4E37D19EF01           vextractf128 xmm7, ymm5, 1
   157 000000EE C5D158EF               vaddpd       xmm5, xmm7
   158 000000F2 C5D17CED               vhaddpd      xmm5, xmm5      ; slow but small
   159 000000F6 C5D35EEC               vdivsd     xmm5, xmm4        ; only low element matters
   160 000000FA C3                     ret

   161 000000FB 7B000000           .size:      dd $ - meanmean_double_avx

    0x7b = 123 bytes

C test koşum

#include <immintrin.h>
#include <stdio.h>
#include <math.h>

static const struct ab_avg {
    double a,b;
    double mean;
} testcases[] = {
    {1, 1, 1},
    {1, 2, 1.45568889},
    {100, 200, 145.568889},
    {2.71, 3.14, 2.92103713},
    {0.57, 1.78, 1.0848205},
    {1.61, 2.41, 1.98965438},
    {0.01, 100, 6.7483058},
};

// see asm comments for order of  arith, harm, quad, geo
__m128 meanmean_float_avx(__m128);       // or float ...
__m256d meanmean_double_avx(__m128d);    // or double ...
int main(void) {
    int len = sizeof(testcases) / sizeof(testcases[0]);
    for(int i=0 ; i<len ; i++) {
        const struct ab_avg *p = &testcases[i];
#if 1
        __m128 arg = _mm_set_ps(0,0, p->b, p->a);
        double res = meanmean_float_avx(arg)[0];
#else
        __m128d arg = _mm_loadu_pd(&p->a);
        double res = meanmean_double_avx(arg)[0];
#endif
        double allowed_diff = (p->b - p->a) / 100000.0;
        double delta = fabs(p->mean - res);
        if (delta > 1e-3 || delta > allowed_diff) {
            printf("%f %f => %.9f but we got %.9f.  delta = %g allowed=%g\n",
                   p->a, p->b, p->mean, res, p->mean - res, allowed_diff);
        }
    }



    while(1) {
        double a = drand48(), b = drand48();  // range= [0..1)
        if (a>b) {
            double tmp=a;
            a=b;
            b=tmp; // sorted
        }
//      a *= 0.00000001;
//      b *= 123156;
        // a += 1<<11;  b += (1<<12)+1;  // float version gets stuck inflooping on 2048.04, 4097.18 at fpthreshold = 4e-5

        // a *= 1<<11 ; b *= 1<<11;   // scaling to large magnitude makes sum of squares loses more precision
        //a += 1<<11; b+= 1<<11;   // adding to large magnitude is hard for everything, catastrophic cancellation
#if 1
        printf("testing float %g, %g\n", a, b);
        __m128 arg = _mm_set_ps(0,0, b, a);
        __m128 res = meanmean_float_avx(arg);
        double quad = res[2], harm = res[1];  // same order as double... for now
#else
        printf("testing double %g, %g\n", a, b);
        __m128d arg = _mm_set_pd(b, a);
        __m256d res = meanmean_double_avx(arg);
        double quad = res[2], harm = res[1];
#endif
        double delta = fabs(quad - harm);
        double allowed_diff = (b - a) / 100000.0; // calculated in double even for the float case.
        // TODO: use the double res as a reference for float res
        // instead of just checking quadratic vs. harmonic mean

        if (delta > 1e-3 || delta > allowed_diff) {
            printf("%g %g we got q=%g, h=%g, a=%g.  delta = %g,  allowed=%g\n",
                   a, b, quad, harm, res[0], quad-harm, allowed_diff);
        }
    }

}

Şununla oluştur:

nasm -felf64 mean-mean.asm &&
gcc -no-pie -fno-pie -g -O2 -march=native mean-mean.c mean-mean.o

Açıkçası AVX destekli bir işlemciye veya Intel SDE gibi bir emülatöre ihtiyacınız var. Yerli AVX desteği, kullanmadan bir ana bilgisayarda derlemek için -march=sandybridgeveya-mavx

Çalıştır: kodlanmış test durumlarını geçer, ancak değişken sürüm için rastgele test durumları genellikle (b-a)/10000soruda belirlenen eşik değerlerde başarısız olur .

$ ./a.out
 (note: empty output before the first "testing float" means clean pass on the constant test cases)
testing float 3.90799e-14, 0.000985395
3.90799e-14 0.000985395 we got q=3.20062e-10, h=3.58723e-05, a=2.50934e-05.  delta = -3.5872e-05,  allowed=9.85395e-09
testing float 0.041631, 0.176643
testing float 0.0913306, 0.364602
testing float 0.0922976, 0.487217
testing float 0.454433, 0.52675
0.454433 0.52675 we got q=0.48992, h=0.489927, a=0.489925.  delta = -6.79493e-06,  allowed=7.23169e-07
testing float 0.233178, 0.831292
testing float 0.56806, 0.931731
testing float 0.0508319, 0.556094
testing float 0.0189148, 0.767051
0.0189148 0.767051 we got q=0.210471, h=0.210484, a=0.21048.  delta = -1.37389e-05,  allowed=7.48136e-06
testing float 0.25236, 0.298197
0.25236 0.298197 we got q=0.274796, h=0.274803, a=0.274801.  delta = -6.19888e-06,  allowed=4.58374e-07
testing float 0.531557, 0.875981
testing float 0.515431, 0.920261
testing float 0.18842, 0.810429
testing float 0.570614, 0.886314
testing float 0.0767746, 0.815274
testing float 0.118352, 0.984891
0.118352 0.984891 we got q=0.427845, h=0.427872, a=0.427863.  delta = -2.66135e-05,  allowed=8.66539e-06
testing float 0.784484, 0.893906
0.784484 0.893906 we got q=0.838297, h=0.838304, a=0.838302.  delta = -7.09295e-06,  allowed=1.09422e-06

FP hataları, bazı girdiler için dörtlü zararın sıfırdan daha az çıkması için yeterlidir.

Ya da a += 1<<11; b += (1<<12)+1;uncommented ile:

testing float 2048, 4097
testing float 2048.04, 4097.18
^C  (stuck in an infinite loop).

Bu sorunların hiçbiri ile olmuyor double. printfÇıktının boş olduğunu görmek için her testten önce yorum yapın ( if(delta too high)bloktan hiçbir şey yok ).

TODO: Dörtlü-zararla nasıl birleştiğine bakmak yerine double, floatsürümü sürüm için referans olarak kullanın .


1

Javascript - 186 bayt

Girdiyi bir sayı dizisi olarak alır. Kodu kısaltmak için J42161217'nin cevabındaki ortalama dönüşümleri kullanır .

Çevrimiçi Deneyin

f=(v,l=[m=(w,k=0)=>w.map(x=>k+=x)&&k/w.length,w=>1/m(w.map(x=>1/x)),w=>Math.E**m(w.map(x=>Math.log(x))),w=>m(w.map(x=>x**2))**.5].map(x=>x(v)).sort((a,b)=>a-b))=>l[3]-l[0]>1e-5?f(l):l[0]

açıklama

f = (
  v,
  l=[
    m=(w,k=0)=>w.map(x=>k+=x)&&k/w.length,  // m = w => arithmetic mean of values in w
    w=>1/m(w.map(x=>1/x)),                  // w => harmonic mean of values in w   
    w=>Math.E**m(w.map(x=>Math.log(x))),    // w => geometric mean of values in w   
    w=>m(w.map(x=>x**2))**.5                // w => quadratic mean of values in w   
  ].map(x=>x(v))                            // get array of each mean using input v, stored in l
  .sort((a,b)=>a-b)                         // sort the outputs
) =>
  l[3] - l[0] > 1e-5 ?                      // is the difference between the largest
                                            // and smallest means > 1/100000?
    f(l) :                                  // if yes, get the mean mean of the means
    l[0]                                    // if no, arbitrarily return the smallest value
                                            // as close enough

Zeki olacağımı ve logaritmalarla olan ilişkiyi uygulayacağımı sanıyordum ama sanırım sen ve J42161217 ilk oraya varmışsınız!
Pureferret

@Pureferret Bunun için kredi almıyorum, açıkça çaldım: D
asgallant

Yine de JavaScript'te yazdın!
Pureferret

1
Bu kolay kısmıydı. Golf zordu.
asgallant

1
TIL doğru şekilde yapılandırılmadı. Cevaba bir TIL linki ekledim.
asgallant


0

SNOBOL4 (CSNOBOL4) , 296 bayt

	X =INPUT
	Y =INPUT
	A =(X + Y) / 2.
	P =X * Y
	G =P ^ 0.5
	H =P / A
	Q =(2 * (A ^ 2) - P) ^ 0.5
O	OUTPUT =EQ(Q,A) Q	:S(END)
	M =A
	N =G
	O =H
	P =Q
	A =(M + N + O + P) / 4
	G =(M * N * O * P) ^ 0.25
	H =4 / (1 / M + 1 / N + 1 / O + 1 / P)
	Q =((M ^ 2 + N ^ 2 + O ^ 2 + P ^ 2) / 4) ^ 0.5	:(O)
END

Çevrimiçi deneyin!

Basit uygulama. Biraz daha golf oynamak için cevabımdan hileyi ilgili bir soruya kullanır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.