Hitung Mean dari dua angka

41

disclaimer: Mean berarti dibuat oleh saya

Tentukan mean aritmetik dari n angka sebagai

M1(x1,...,xn)=x1+x2+...+xnn
Tentukan mean geometrik darinangka sebagai
M0(x1,...,xn)=x1x2...xnn
Tentukan rata-rata harmonik dariangka sebagai Tentukan rata-rata kuadratik dariangkasebagai Mean Mean () didefinisikan sebagai berikut: Tentukan empat urutan (n
M1(x1,...,xn)=n1x2+1x2+...+1xn
n
M2(x1,...,xn)=x12+x22+...+xn2n
MMak,bk,ck,dk ) sebagai
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)
Semua empat urutan konvergen ke nomor yang sama,MM(x1,x2,...,xn) .

Contoh

Mean Mean 1 dan 2 dihitung sebagai berikut: mulai dengan

a0=(1+2)/2=1.5,b0=12=21.4142,c0=211+12=431.3333,d0=12+222=521.5811.
Kemudian
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.
Perhitungan lebih lanjut dari urutan harus jelas. Dapat dilihat bahwa mereka bertemu ke nomor yang sama, kira-kira1.45568889.

Tantangan

Mengingat dua bilangan real positif, a dan b ( a<b ), menghitung mereka Berarti rata-rata MM(a,b) .

Uji kasus

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

Catatan

  • Program Anda valid jika perbedaan antara output dan output yang benar tidak lebih besar dari 1/100000 dari nilai absolut perbedaan antara nomor input.
  • Outputnya harus satu nomor.

Ini adalah , jadi kode terpendek menang!

some one
sumber
Tautan kotak pasir
seseorang
Agak terkait: Hitung Aritmetika – Geometris Rata
user202729
11
Seberapa tepat kita seharusnya?
Perwujudan Ketidaktahuan
2
Berhubungan erat
Giuseppe
1
Bisakah kita mengasumsikan input pertama selalu lebih kecil dari yang kedua, seperti dalam semua kasus pengujian Anda? (Jika tidak, saya akan
mengembalikan

Jawaban:

14

Bahasa Wolfram (Mathematica) , 52 byte

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

Cobalah online!

Dalam pendekatan pertama saya, saya menggunakan builtin ini
Mean GeometricMean HarmonicMeandanRootMeanSquare

Berikut adalah beberapa penggantian untuk menghemat byte

HarmonicMean-> 1/Mean[1/x] oleh @Robin Ryder (3 byte disimpan)
GeometricMean-> E^Mean@Log@xoleh @A. Rex (2 byte disimpan)
RootMeanSquare-> Mean[x^2]^.5oleh @A. Rex (4 byte disimpan)

akhirnya kami dapat menetapkan Meanuntuk M(seperti yang diusulkan oleh @ovs) dan Hemat 5 byte lagi

J42161217
sumber
Simpan 2 byte dengan pengodean ulang GeometricMean
Robin Ryder
@RobinRyder, saya percaya maksud Anda Harmonic .. bagus!
J42161217
1
Hemat 8 byte lagi :#//.x_:>N@{Mean@x,E^Mean@Log@x,1/Mean[1/x],Mean[x^2]^.5}&
A. Rex
@ov diedit .....
J42161217
10

R, 70 69 67 byte

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

Cobalah online!

-1 byte dengan pengkondisian yang lebih baik.
-2 byte dengan beralih ke basis 2.

Seperti beberapa jawaban lain, ini menggunakan ekspresi mean geometrik sebagai rata-rata aritmatika pada skala log (di sini dalam basis 2):

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

Hal ini juga menggunakan fakta bahwa k,dkakbkck , yaitu dk=max(ak,bk,ck,dk) . Kondisi ak=bk=ck=dk Oleh karena itu setara dengan dk=M1(ak,bk,ck,dk) , yang saya gunakan di loop while; ini dicapai dengan menyalahgunakan sintakswhileyang hanya mempertimbangkan elemen pertama ketika kondisinya adalah vektor, maka urutan penyimpanannya. (Perhatikan bahwa kita bisa juga menggunakanck bukan karena merupakan minimal empat, tapi kami tidak bisa menggunakanak ataubk dalam kondisi.)

Ketika kita keluar dari loop sementara, xadalah vektor konstan. Final ?xmenghitung rata-rata untuk menguranginya menjadi skalar.

Robin Ryder
sumber
1
Bukankah seharusnya bukannya l o g x n ? lnxnlogxn
Tau
@Tau Ya, saya yang menunjukkan logaritma natural oleh , yang merupakan default di R. Anyway, saya sekarang telah berubah ke basis 2 logaritma untuk -2 byte. log
Robin Ryder
6

J , 34 byte

(31 sebagai ekspresi tanpa penugasan ke variabel f)

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

Cobalah online!

Untuk fungsi adan b, a &.: b("a di bawah b" ( tantangan terkait )) setara dengan (b inv) a b- menerapkan b, lalu a, lalu kebalikan dari b. Dalam hal ini, rata-rata geometrik / harmonik / kuadrat adalah rata-rata aritmatika "di bawah", inversi, dan kuadrat.

pengguna202729
sumber
5

TI-BASIC, 42 35 34 byte

-1 byte terima kasih kepada @SolomonUcko

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

Input adalah daftar dua bilangan bulat di Ans.
Output disimpan Ansdan dicetak secara otomatis ketika program selesai.

Rumus yang digunakan untuk rata-rata geometris, harmonik, dan kuadrat didasarkan pada penjelasan user202729 .

Contoh:

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

Penjelasan:
(Baris baru telah ditambahkan untuk klarifikasi. Mereka TIDAK muncul dalam kode.)

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

Catatan:

TI-BASIC adalah bahasa tokenized. Jumlah karakter tidak sama dengan jumlah byte.

e^(apakah ini token satu byte.

^-1digunakan untuk ini tanda satu-byte.
Saya memilih untuk menulis ^-1sebagai gantinya karena token terlihat seperti ֿ¹ketika di blok kode.

√(apakah ini token satu byte.

ΔList(adalah ini tanda dua-byte.

Tau
sumber
Saya pikir Anda dapat menyimpan tanda kurung dengan menempatkan mean geometrik terakhir.
Solomon Ucko
@SolomonUcko ah, terima kasih telah memperhatikan! Tidak mempertimbangkan itu sebelumnya.
Tau
max(DeltaList(Ans-> variance(Ans.
lirtosiast
5

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

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];}

-5 byte terima kasih kepada @PeterCordes .
-15 byte lebih banyak berkat @PeterCordes , yang terinspirasi dari jawaban R @RobinRyder .
+4 byte karena saya berasumsi input sudah dipesan sebelumnya.
-27 byte terima kasih kepada @ OlivierGrégoire .

Cobalah online.

Penjelasan:

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
Kevin Cruijssen
sumber
Dalam C Anda bisa f+=Math.abs(d-D)<1e-9;dan mendapatkan konversi implisit dari hasil perbandingan boolean ke integer 0/1 lalu double. Apakah Java memiliki sintaks yang kompak untuk itu? Atau apakah mungkin untuk dilakukan f+=Math.abs(d-D)dan kemudian memeriksa bahwa jumlah perbedaan absolut cukup kecil ?
Peter Cordes
1
Yup, untuk kasus pengujian Anda, f>1e-8berfungsi sebagai kondisi loop: 229 byte. 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];}. Dengan 1e-9, ini berjalan lebih lambat (sekitar dua kali waktu CPU), harus melakukan lebih banyak iterasi untuk mendapatkan 4 * pada dasarnya d-Dyang kecil. Dengan 1e-7, ini tentang kecepatan yang sama dengan 1e-8. Dengan 1e-6, beberapa digit tambahan berbeda untuk satu kasing.
Peter Cordes
1
@ Jawaban RobinRyder menunjukkan bahwa mean kuadratik selalu yang terbesar, dan harmonik selalu yang terkecil, jadi mungkin Anda bisa membuang fseluruhnya dan hanya memeriksa a[3]-a[2]<4e-9.
Peter Cordes
1
@PeterCordes l==2||maksud Anda ( golf to l<3|). Tapi ya, poin bagus; Saya sudah menambahkannya. :)
Kevin Cruijssen
2
180 byte dengan menggabungkan pengurang agregat.
Olivier Grégoire
3

Arang , 40 byte

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

Cobalah online! Tautan adalah untuk mengucapkan versi kode. Mengambil input sebagai array angka. Penjelasan:

W‹⌊θ⌈θ

Ulangi sementara array berisi nilai yang berbeda ...

≔⟦....⟧θ

... ganti array dengan daftar nilai:

∕ΣθLθ

... yang berarti ...

XΠθ∕¹Lθ

... rerata geometris ...

∕LθΣ∕¹θ

... rata-rata harmonik ...

₂∕ΣXθ²Lθ

... dan root mean square.

I⊟θ

Keluarkan elemen array ke string dan cetak secara implisit.

Neil
sumber
3

PowerShell , 182 180 183 byte

$f={$a=$c=$d=$n=0
$b=1
$m=[math]
$args|%{$n++
$a+=$_
$b*=$_
$c+=1/$_
$d+=+$_*$_}
$p=($a/$n),$m::pow($b,1/$n),($n/$c),$m::sqrt($d/$n)|%{$m::round($_,9)}
if($p-ne$p[0]){$p=&$f @p}$p[0]}

Cobalah online!

Andrei Odegov
sumber
171 byte
mazzy
@ Mazzy, mengesankan :)
Andrei Odegov
3

05AB1E , 26 24 23 byte

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

Cobalah secara online atau lihat langkah-langkah semua kasus uji .

-1 byte terima kasih kepada @Grimy .

23 byter alternatif untuk Geometric mean:

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

Cobalah secara online atau lihat langkah-langkah semua kasus uji .

Penjelasan:

Δ         # 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)
Kevin Cruijssen
sumber
23:Δ©P®gzm®ÅA®zÅAz®nÅAt)}н
Grimmy
@ Terima kasih kotor! Tidak percaya saya tidak berpikir untuk menggunakan panjangnya alih-alih Yuntuk 2/4. :)
Kevin Cruijssen
1
Lain 23 yang atasannya menunjukkan kesamaan mean geometrik dengan yang lainnya: Δ©ÅA®.²ÅAo®zÅAz®nÅAt)}н. Sayangnya, sepertinya kita tidak bisa memperbaiki semua ÅAitu.
Grimmy
@ Grimy Oh, saya suka versi kedua ini. :) EDIT: Ups .. terima kasih sudah memperhatikan kesalahan saya dalam penjelasan ..>.>
Kevin Cruijssen
Saya tidak memprogram di 05ab1e dengan sangat baik, tetapi bisakah Anda menghitung jumlah dan kemudian membaginya dengan panjangnya nanti?
seseorang
2

Jelly , 25 24 byte

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

Cobalah online!

Penjelasan

                    µÐ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
Nick Kennedy
sumber
Saya cukup buruk di Jelly, tetapi bisakah sesuatu yang mirip P*İLbekerja untuk arti geometris?
seseorang
@ Seseorang harus P*Lİ$jadi tidak akan menghemat byte. Itu berarti saya bisa membawa Æmturun garis tanpa biaya byte, tapi saya cukup suka fakta masing-masing saat ini memiliki rata-rata aritmatika pada intinya.
Nick Kennedy
2

Python 3 , 152 byte

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)

Cobalah online!

Fungsi rekursif f, akan menyatu dengan presisi floating point. Pada prinsipnya bekerja untuk semua daftar angka positif dari ukuran apa pun , tetapi dibatasi oleh batas rekursi Python kesalahan pembulatan untuk beberapa kasus uji.


Atau, memilih presisi 9 desimal:

Python 3 , 169 byte

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)

Cobalah online!

Jitse
sumber
1

C # , 173 byte

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

Cobalah online!

penerbang
sumber
2
Ini sepertinya benar-benar pada variabel yang harus dilewati. Juga, Anda harus memasukkan using Systemdan using System.Linqdalam hitungan byte Anda, karena mereka diperlukan untuk menjalankan program. Anda dapat mengubah kompiler Anda menjadi C # Visual Interactive Compiler, yang tidak memerlukan impor itu. Juga, 1.0->1d
Perwujudan Ketidaktahuan
1

Bersihkan , 124 byte

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]

Cobalah online!

Lakukan operasi sampai hasilnya berhenti berubah.

Hore untuk floating point presisi terbatas!

Suram
sumber
1

Pyth, 32 byte

h.Wt{H[.OZ@*[email protected]^R2Z2

Cobalah online di sini , atau verifikasi semua kasus uji (bilah dua, lihat catatan di bawah) sekaligus di sini . Menerima input sebagai daftar.

Tampaknya ada beberapa masalah dengan pembulatan, karena input tertentu tidak bertemu dengan benar ketika seharusnya tidak. Secara khusus, test case 0.01 100macet pada nilai-nilai [6.748305820749738, 6.748305820749738, 6.748305820749739, 6.748305820749738], dan test case 1.61 2.41macet di [1.9896543776640825, 1.9896543776640825, 1.9896543776640827, 1.9896543776640825]- perhatikan dalam kedua kasus bahwa rata-rata ke-3 (rata-rata harmonik) berbeda dari yang lain.

Saya tidak yakin apakah masalah ini membatalkan entri saya, tetapi saya tetap mempostingnya karena seharusnya berfungsi. Jika ini tidak dapat diterima, itu dapat diperbaiki dengan menanamkan .RRTsebelum [, untuk mengitari masing-masing sarana ke 10 tempat desimal, seperti yang terlihat dalam rangkaian uji ini .

h.Wt{H[.OZ@*[email protected]^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@*[email protected]^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
Sok
sumber
Karena saya cukup yakin perhitungan berulang tidak akan melompat ke nilai sebelumnya, Anda dapat mengganti .Wt{Hdengan uuntuk -4 byte (dan mengubah Zke G)
ar4093
1

Japt v2.0a0 -g, 42 38 byte

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

Pasti ada jalan yang lebih pendek ... Ini adalah keburukan! Disimpan 4 byte berkat @Shaggy!

Cobalah

Perwujudan Ketidaktahuan
sumber
38 byte . Tapi saya setuju, pasti ada cara yang lebih singkat!
Shaggy
1

C # (Visual C # Interactive Compiler) , 177 byte

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;

Terima kasih kepada @KevinCruijjsen karena menunjukkan bahwa menggunakan presisi floating point menyebabkan masalah! Akan menjadi 163 byte jika ganda itu sangat tepat.

Cobalah online!

Perwujudan Ketidaktahuan
sumber
Dua test case terakhir menghasilkan StackOverflowExceptionketelitian floating point. Alih-alih c==g[0]Anda bisa melakukan sesuatu seperti Math.Abs(c-g[0])<1e-9. Cobalah online.
Kevin Cruijssen
@KevinCruijssen Terima kasih, ini sangat merepotkan dengan angka floating point
Perwujudan Ketidaktahuan
1

kode mesin x86 (SIMD 4x float menggunakan 128-bit SSE1 & AVX) 94 byte

kode mesin x86 (SIMD 4x ganda menggunakan 256-bit AVX) 123 byte

floatlulus uji kasus dalam pertanyaan, tetapi dengan ambang loop-keluar cukup kecil untuk membuat itu terjadi, mudah untuk terjebak dalam loop tak terbatas dengan input acak.

Instruksi presisi tunggal yang dikemas dengan SSE1 panjangnya 3 byte, tetapi instruksi SSE2 dan AVX sederhana sepanjang 4 byte. (Instruksi skalar-tunggal seperti sqrtssjuga panjangnya 4 byte, itulah sebabnya saya menggunakan sqrtpsmeskipun saya hanya peduli pada elemen rendah. Bahkan tidak lebih lambat dari sqrtss pada perangkat keras modern). Saya menggunakan AVX untuk tujuan non-destruktif untuk menghemat 2 byte vs movaps + op.
Dalam versi ganda kita masih dapat melakukan pasangan movlhpsuntuk menyalin potongan 64-bit (karena seringkali kita hanya peduli pada elemen rendah dari jumlah horizontal). Jumlah horisontal dari vektor 256-bit SIMD juga membutuhkan tambahan vextractf128untuk mendapatkan setengah tinggi, vs strategi 2x lambat tapi kecil haddpsuntuk float . Itudoubleversi juga membutuhkan konstanta 2x 8-byte, bukannya 2x 4-byte. Secara keseluruhan itu keluar di dekat dengan 4/3 ukuran floatversi.

mean(a,b) = mean(a,a,b,b)untuk keempat cara ini , jadi kita bisa menduplikasi input hingga 4 elemen dan tidak pernah harus mengimplementasikan length = 2. Jadi, kita dapat hardcode geometric mean sebagai 4th-root = sqrt (sqrt), misalnya. Dan kita hanya perlu satu konstanta FP 4.0,.

Kami memiliki vektor SIMD tunggal dari semua 4 [a_i, b_i, c_i, d_i]. Dari itu, kami menghitung 4 berarti sebagai skalar dalam register terpisah, dan mengocoknya kembali untuk iterasi berikutnya. (Operasi horizontal pada vektor SIMD tidak nyaman, tetapi kita perlu melakukan hal yang sama untuk semua 4 elemen dalam cukup banyak kasus yang menyeimbangkan. Saya mulai pada versi x87 ini, tetapi sudah sangat lama dan tidak menyenangkan.)

Kondisi loop-exit }while(quadratic - harmonic > 4e-5)(atau konstanta yang lebih kecil untuk double) didasarkan pada jawaban R @ RobinRyder , dan jawaban Java Kevin Cruijssen : mean kuadratik selalu merupakan besaran terbesar , dan mean harmonik selalu yang terkecil (mengabaikan kesalahan pembulatan). Jadi kita dapat memeriksa delta antara keduanya untuk mendeteksi konvergensi. Kami mengembalikan mean aritmatika sebagai hasil skalar. Biasanya antara keduanya dan mungkin yang paling rentan terhadap kesalahan pembulatan.

Versi float : callable seperti float meanmean_float_avx(__m128);dengan nilai arg dan return di xmm0. (Jadi x86-64 System V, atau Windows x64 vectorcall, tetapi tidak x64 fastcall.) Atau nyatakan tipe-kembali sebagai __m128sehingga Anda bisa mendapatkan kuadrat dan rata-rata harmonik untuk pengujian.

Membiarkan ini mengambil 2 floatargumen terpisah dalam xmm0 dan xmm1 akan membutuhkan 1 byte tambahan: kita membutuhkan sebuah shufpsdengan imm8 (bukan hanya unpcklps xmm0,xmm0) untuk mengocok bersama dan menduplikasi 2 input.

    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

(Daftar NASM dibuat dengan nasm -felf64 mean-mean.asm -l/dev/stdout | cut -b -34,$((34+6))-. Strip bagian daftar dan memulihkan sumber dengan cut -b 34- > mean-mean.asm)

Jumlah horizontal SIMD dan bagi dengan 4 (yaitu rata-rata aritmatika) diimplementasikan dalam fungsi terpisah yang kita call(dengan pointer fungsi untuk mengamortisasi biaya alamat). Dengan 4/xsebelum / sesudah, atau x^2sebelum dan sesudah sqrt, kita mendapatkan mean harmonik dan rata-rata kuadratik. (Sungguh menyakitkan untuk menulis divinstruksi ini alih-alih mengalikannya dengan representasi yang tepat 0.25.)

Mean geometrik diimplementasikan secara terpisah dengan multiprt dan dirantai sqrt. Atau dengan satu sqrt pertama untuk mengurangi besarnya eksponen dan mungkin membantu presisi numerik. log tidak tersedia, hanya floor(log2(x))melalui AVX512 vgetexpps/pd. Exp adalah semacam tersedia melalui AVX512ER (hanya Xeon Phi), tetapi dengan hanya 2 ^ -23 presisi.

Mencampur instruksi AVX 128-bit dan warisan SSE bukan masalah kinerja. Mencampurkan 256-bit AVX dengan legacy SSE bisa di Haswell, tetapi di Skylake itu hanya berpotensi menciptakan ketergantungan palsu potensial untuk instruksi SSE. Saya pikir doubleversi saya menghindari rantai dep-loop yang tidak perlu dilakukan, dan kemacetan pada div / sqrt latency / throughput.

Versi ganda:

   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

Harness uji C

#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);
        }
    }

}

Dibangun dengan:

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

Tentunya Anda membutuhkan CPU dengan dukungan AVX, atau emulator seperti Intel SDE. Untuk mengkompilasi pada host tanpa dukungan AVX asli, gunakan -march=sandybridgeatau-mavx

Jalankan: melewati kotak uji hard-coded, tetapi untuk versi float, kotak uji acak sering gagal (b-a)/10000ambang batas yang ditetapkan dalam pertanyaan.

$ ./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

Kesalahan FP sudah cukup sehingga quad-harm keluar kurang dari nol untuk beberapa input.

Atau dengan a += 1<<11; b += (1<<12)+1;uncommented:

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

Tak satu pun dari masalah ini terjadi double. Komentari printfsebelum setiap tes untuk melihat bahwa output kosong (tidak ada dari if(delta too high)blok).

TODO: gunakan doubleversi sebagai referensi untuk floatversi, bukan hanya melihat bagaimana mereka konvergen dengan quad-harm.

Peter Cordes
sumber
1

Javascript - 186 byte

Mengambil input sebagai array angka. Menggunakan transformasi rata-rata dalam jawaban J42161217 untuk mempersingkat kode.

Cobalah secara Online

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]

Penjelasan

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
sangat penting
sumber
Saya pikir saya akan menjadi pintar dan menerapkan hubungan dengan logaritma tetapi sepertinya Anda dan J42161217 sampai di sana dulu!
Pureferret
@ Murniferret Saya tidak mengambil kredit untuk itu, saya terang-terangan mencurinya: D
asgallant
Anda menulisnya dalam JavaScript!
Pureferret
1
Itu bagian yang mudah. Bermain golf itu sulit.
asgallant
1
TIL tidak dikonfigurasi dengan benar. Saya menambahkan tautan TIL ke jawabannya.
asgallant
0

Perl 5 , 92 72 byte

sub f{@_=map{$m=$_;sum(map$_**$m/@_,@_)**(1/$m)}1,1e-9,-1,2for 1..9;pop}

Cobalah online!

... menggunakan beberapa trik kotor.

Kjetil S.
sumber
0

SNOBOL4 (CSNOBOL4) , 296 byte

	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

Cobalah online!

Implementasi langsung. Menggunakan trik dari jawaban saya untuk pertanyaan terkait golf lebih banyak.

Giuseppe
sumber