Tính giá trị trung bình của hai số


41

từ chối trách nhiệm: ý nghĩa trung bình được tạo ra bởi tôi

Xác định giá trị trung bình số học của số là Xác định giá trị trung bình hình học của số là Xác định giá trị trung bình hài của số là Xác định trung bình bậc hai của số là M_2 (x_1, ..., x_n) = \ root \ of {\ frac {x_1 ^ 2 + x_2 ^ 2 + ... + x_n ^ 2} {n}} Nghĩa trung bình ( M_M ) được định nghĩa như sau: Xác định bốn chuỗi ( a_k, b_k, c_k, d_k ) là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)
Tất cả bốn chuỗi đều hội tụ cùng số,MM(x1,x2,...,xn) .

Thí dụ

Giá trị trung bình trung bình của 1 và 2 được tính như sau: bắt đầu bằng

a0=(1+2)/2=1.5,b0=12=21.4142,c0=211+12=431.3333,d0=12+222=521.5811.
Sau đó
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.
Việc tính toán thêm các trình tự nên rõ ràng. Có thể thấy rằng chúng hội tụ đến cùng một số, xấp xỉ 1.45568889 .

Thử thách

Cho hai số thực dương, ab ( a<b ), tính MM(a,b) trung bình của chúng (a, b) .

Các trường hợp thử nghiệm

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

Ghi chú

  • Chương trình của bạn hợp lệ nếu chênh lệch giữa đầu ra của nó và đầu ra đúng không lớn hơn 1/100000 giá trị tuyệt đối của chênh lệch giữa các số đầu vào.
  • Đầu ra phải là một số duy nhất.

Đây là , vì vậy đoạn mã ngắn nhất sẽ thắng!




11
Làm thế nào chính xác là chúng ta phải được?
Hiện thân của sự thiếu hiểu biết


1
Chúng tôi có thể giả sử đầu vào đầu tiên luôn nhỏ hơn đầu vào thứ hai, như trong tất cả các trường hợp thử nghiệm của bạn không? (Nếu không tôi sẽ trả lại câu trả lời Java của tôi.)
Kevin Cruijssen

Câu trả lời:


14

Ngôn ngữ Wolfram (Mathicala) , 52 byte

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

Hãy thử trực tuyến!

Trong cách tiếp cận đầu tiên của tôi, tôi đã sử dụng các nội dung này
Mean GeometricMean HarmonicMeanRootMeanSquare

Dưới đây là một số thay thế để lưu byte

HarmonicMean-> 1/Mean[1/x] bởi @Robin Ryder (đã lưu 3 byte)
GeometricMean-> E^Mean@Log@xbởi @A. Rex (đã lưu 2 byte)
RootMeanSquare-> Mean[x^2]^.5bởi @A. Rex (đã lưu 4 byte)

cuối cùng chúng ta có thể gán Meancho M(như được đề xuất bởi @ovs) và lưu thêm 5 byte


Lưu 2 byte bằng cách mã hóa hình họcMean
Robin Ryder

@RobinRyder Tôi tin bạn có nghĩa là Harmonic .. tốt đẹp!
J42161217

1
Lưu thêm 8 byte :#//.x_:>N@{Mean@x,E^Mean@Log@x,1/Mean[1/x],Mean[x^2]^.5}&
A. Rex

@ovs đã chỉnh sửa .....
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

Hãy thử trực tuyến!

-1 byte với điều hòa tốt hơn.
-2 byte bằng cách chuyển sang cơ sở 2.

Giống như một số câu trả lời khác, điều này sử dụng biểu thức của ý nghĩa hình học như một trung bình số học trên thang đo nhật ký (ở đây trong cơ sở 2):

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

Nó cũng sử dụng thực tế là , tức là . Do đó, điều kiện tương đương với , đó là những gì tôi sử dụng trong vòng lặp while; điều này đạt được bằng cách lạm dụng cú pháp chỉ xem xét phần tử đầu tiên khi điều kiện là một vectơ, do đó thứ tự lưu trữ phương tiện. (Lưu ý rằng chúng tôi cũng có thể sử dụng thay vì nó là tối thiểu là bốn, nhưng chúng tôi không thể sử dụng hoặc trong tình trạng này.)k,dkakbkckdk=max(ak,bk,ck,dk)ak=bk=ck=dkdk=M1(ak,bk,ck,dk)c kwhileckakbk

Khi chúng ta thoát khỏi vòng lặp while, xlà một vectơ không đổi. Cuối cùng ?xtính toán ý nghĩa của nó để giảm nó xuống một vô hướng.


1
Không nên là thay vì ? l o g x nlnxnlogxn
Tàu

@Tau Có, tôi đã biểu thị logarit tự nhiên bằng , đó là mặc định trong R. Dù sao, bây giờ tôi đã thay đổi nó thành cơ sở 2 logarit cho -2 byte. log
Robin Ryder

6

J , 34 byte

(31 dưới dạng biểu thức không có gán cho biến f)

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

Hãy thử trực tuyến!

Đối với các hàm ab, a &.: b("a dưới b" ( thách thức liên quan )) tương đương với (b inv) a b- áp dụng b, sau đó a, sau đó nghịch đảo của b. Trong trường hợp này, trung bình hình học / hài hòa / bậc hai là trung bình số học "dưới" logarit, đảo ngược và bình phương tương ứng.


5

TI-BASIC, 42 35 34 byte

-1 byte nhờ @SolomonUcko

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

Đầu vào là danh sách hai số nguyên trong Ans.
Đầu ra được lưu trữ Ansvà được tự động in ra khi chương trình hoàn thành.

Các công thức được sử dụng cho các phương tiện hình học, hài hòa và bậc hai được dựa trên lời giải thích của người dùng202729 .

Thí dụ:

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

Giải thích:
(Dòng mới đã được thêm vào để làm rõ. Chúng KHÔNG xuất hiện trong mã.)

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

Ghi chú:

TI-BASIC là một ngôn ngữ được mã hóa. Số lượng ký tự không bằng số byte.

e^(này một byte token.

^-1được sử dụng cho này một byte token.
Tôi đã chọn để viết ^-1thay vì mã thông báo trông giống như ֿ¹khi ở trong một khối mã.

√(này một byte token.

ΔList(này hai byte token.


Tôi nghĩ bạn có thể lưu dấu ngoặc đơn bằng cách đặt giá trị trung bình hình học cuối cùng.
Solomon Ucko

@SolomonUcko ah, cảm ơn vì đã chú ý! Không xem xét điều đó trước đây.
Tàu

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 nhờ @PeterCordes .
-15 byte nhiều hơn nhờ @PeterCordes , lấy cảm hứng từ câu trả lời R của @RobinRyder .
+4 byte bởi vì tôi giả sử các đầu vào được đặt hàng trước.
-27 byte nhờ @ OlivierGrégoire .

Hãy thử trực tuyến.

Giải trình:

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

Trong C, bạn có thể f+=Math.abs(d-D)<1e-9;và nhận chuyển đổi ngầm định từ kết quả so sánh boolean sang số nguyên 0/1 và sau đó double. Java có bất kỳ cú pháp nhỏ gọn nào cho điều đó không? Hoặc có thể làm f+=Math.abs(d-D)và sau đó kiểm tra xem tổng số chênh lệch tuyệt đối có đủ nhỏ không?
Peter Cordes

1
Yup, đối với các trường hợp thử nghiệm của bạn, f>1e-8hoạt động như một điều kiện vòng lặp: 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];}. Với 1e-9, nó chạy chậm hơn (khoảng gấp đôi thời gian của CPU), phải thực hiện nhiều lần lặp hơn để giảm về cơ bản 4 * d-D. Với 1e-7, nó có cùng tốc độ với 1e-8. Với 1e-6, một số chữ số khác nhau cho một trường hợp.
Peter Cordes

1
Câu trả lời của @ RobinRyder chỉ ra rằng trung bình bậc hai luôn là lớn nhất và điều hòa luôn luôn nhỏ nhất, vì vậy có lẽ bạn có thể bỏ fhoàn toàn và chỉ kiểm tra a[3]-a[2]<4e-9.
Peter Cordes

1
@PeterCordes l==2||bạn có nghĩa là (chơi gôn l<3|). Nhưng vâng, điểm tốt; Tôi đã thêm nó. :)
Kevin Cruijssen

2
180 byte bằng cách tổng hợp các bộ giảm tốc tổng hợp.
Olivier Grégoire

3

Than , 40 byte

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

Hãy thử trực tuyến! Liên kết là phiên bản dài dòng của mã. Đưa đầu vào như một mảng số. Giải trình:

W‹⌊θ⌈θ

Lặp lại trong khi mảng chứa các giá trị khác nhau ...

≔⟦....⟧θ

... thay thế mảng bằng một danh sách các giá trị:

∕ΣθLθ

... nghĩa...

XΠθ∕¹Lθ

... ý nghĩa hình học ...

∕LθΣ∕¹θ

... ý nghĩa hài hòa ...

₂∕ΣXθ²Lθ

... và căn bậc có nghĩa là hình vuông.

I⊟θ

Truyền một phần tử của mảng thành chuỗi và in ngầm.




3

05AB1E , 26 24 23 byte

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

Hãy thử trực tuyến hoặc xem các bước của tất cả các trường hợp thử nghiệm .

-1 byte nhờ @Grimy .

23 thay thế cho ý nghĩa hình học:

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

Hãy thử trực tuyến hoặc xem các bước của tất cả các trường hợp thử nghiệm .

Giải trình:

Δ         # 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 Cảm ơn! Không thể tin rằng tôi đã nghĩ về việc sử dụng độ dài thay vì Ycho 2/4. :)
Kevin Cruijssen

1
23 khác mà Betters cho thấy sự tương tự của ý nghĩa hình học với những người khác : Δ©ÅA®.²ÅAo®zÅAz®nÅAt)}н. Thật không may, có vẻ như chúng ta không thể cấu trúc lại tất cả những thứ ÅAđó.
Grimmy

@Grimy ơi, tôi thích phiên bản thứ hai này. :) EDIT: Rất tiếc .. cảm ơn vì đã nhận thấy lỗi của tôi trong phần giải thích ..>.>
Kevin Cruijssen

Tôi không lập trình rất tốt trong 05ab1e, nhưng bạn có thể tính tổng và sau đó chia tất cả cho chiều dài sau không?
ai đó

2

Thạch , 25 24 byte

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

Hãy thử trực tuyến!

Giải trình

                    µÐ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

Tôi khá tệ ở Jelly, nhưng có thể một cái gì đó tương tự như P*İLhoạt động cho ý nghĩa hình học?
ai đó

@someone nó sẽ cần phải P*Lİ$như vậy sẽ không lưu byte. Điều đó có nghĩa là tôi có thể đưa Æmxuống một dòng mà không tốn chi phí byte, nhưng tôi khá thích thực tế mỗi dòng hiện có một ý nghĩa số học ở cốt lõi của nó.
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)

Hãy thử trực tuyến!

Hàm đệ quy f, sẽ hội tụ đến độ chính xác của dấu phẩy động. Nguyên tắc hoạt động cho tất cả các danh sách các số dương kích thước bất kỳ , nhưng bị giới hạn bởi đệ quy của Python giới hạn một lỗi làm tròn cho một số trường hợp thử nghiệm.


Ngoài ra, giải quyết cho 9 số thập phân chính xác:

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)

Hãy thử trực tuyến!


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

Hãy thử trực tuyến!


2
Điều này dường như thực sự trên một biến phải được thông qua. Ngoài ra, bạn phải bao gồm using Systemusing System.Linqtrong số byte của bạn, vì chúng được yêu cầu để chương trình chạy. Bạn có thể thay đổi trình biên dịch của mình thành Trình biên dịch tương tác trực quan C #, không cần nhập. Ngoài ra, 1.0->1d
Hiện thân của sự thiếu hiểu biết

1

Sạch sẽ , 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]

Hãy thử trực tuyến!

Thực hiện thao tác cho đến khi kết quả dừng thay đổi.

Thắng cho điểm nổi chính xác hạn chế!


1

Bình thường, 32 byte

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

Dùng thử trực tuyến tại đây hoặc xác minh tất cả các trường hợp thử nghiệm (thanh hai, xem ghi chú bên dưới) cùng một lúc tại đây . Chấp nhận đầu vào như một danh sách.

Dường như có một số vấn đề với làm tròn, vì một số đầu vào nhất định không hội tụ chính xác khi chúng cần. Cụ thể, trường hợp thử nghiệm 0.01 100bị kẹt ở các giá trị [6.748305820749738, 6.748305820749738, 6.748305820749739, 6.748305820749738]và trường hợp thử nghiệm 1.61 2.41bị kẹt tại [1.9896543776640825, 1.9896543776640825, 1.9896543776640827, 1.9896543776640825]- lưu ý trong cả hai trường hợp rằng trung bình thứ 3 (trung bình hài) khác với các giá trị khác.

Tôi không chắc vấn đề này có làm mất hiệu lực mục nhập của tôi không, nhưng dù sao tôi cũng sẽ đăng nó vì nó sẽ hoạt động. Nếu điều này không được chấp nhận, nó có thể được sửa bằng cách kích hoạt .RRTtrước [, để làm tròn mỗi phương tiện đến 10 chữ số thập phân, như đã thấy trong bộ thử nghiệm này .

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

Vì tôi khá chắc chắn rằng phép tính lặp lại sẽ không chuyển sang các giá trị trước đó, bạn có thể thay thế .Wt{Hbằng u-4 byte (và thay đổi Zthành G)
ar4093


1

C # (Trình biên dịch tương tác Visual C #) , 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;

Cảm ơn @KevinCruijjsen đã chỉ ra rằng việc sử dụng độ chính xác của dấu phẩy động đã gây ra sự cố! Sẽ là 163 byte nếu nhân đôi hoàn toàn chính xác.

Hãy thử trực tuyến!


Hai trường hợp kiểm tra cuối cùng cho một StackOverflowExceptiondo độ chính xác điểm nổi. Thay vì c==g[0]bạn có thể làm một cái gì đó như Math.Abs(c-g[0])<1e-9. Hãy thử trực tuyến.
Kevin Cruijssen

@KevinCruijssen Cảm ơn, thật đau đớn khi đối phó với các số dấu phẩy động
Hiện thân của sự thiếu hiểu biết

1

Mã máy x86 (SIMD 4x float sử dụng SSE1 & AVX 128 bit) 94 byte

Mã máy x86 (gấp đôi SIMD sử dụng AVX 256 bit) 123 byte

floatvượt qua các trường hợp kiểm tra trong câu hỏi, nhưng với ngưỡng thoát vòng lặp đủ nhỏ để thực hiện điều đó, thật dễ dàng để nó bị mắc kẹt trong một vòng lặp vô hạn với các đầu vào ngẫu nhiên.

Các lệnh chính xác được đóng gói đơn SSE1 dài 3 byte, nhưng các lệnh SSE2 và AVX đơn giản dài 4 byte. (Các lệnh đơn vô hướng như sqrtsscũng dài 4 byte, đó là lý do tại sao tôi sử dụng sqrtpsmặc dù tôi chỉ quan tâm đến phần tử thấp. Nó thậm chí không chậm hơn sqrts trên phần cứng hiện đại). Tôi đã sử dụng AVX cho đích không phá hủy để lưu 2 byte so với Movaps + op.
Trong phiên bản kép, chúng ta vẫn có thể thực hiện một vài lần movlhpsđể sao chép các đoạn 64 bit (vì chúng ta thường chỉ quan tâm đến phần tử thấp của tổng số ngang). Tổng chiều ngang của vectơ SIMD 256 bit cũng cần thêm một phần vextractf128để có được một nửa cao, so với chiến lược 2x chậm nhưng nhỏ haddpsđể nổi . Cácdoublephiên bản cũng cần 2x hằng số 8 byte, thay vì 2x 4 byte. Nhìn chung, nó có kích thước gần bằng 4/3 kích thước của floatphiên bản.

mean(a,b) = mean(a,a,b,b)đối với cả 4 phương tiện này , vì vậy chúng tôi chỉ cần nhân đôi đầu vào tối đa 4 phần tử và không bao giờ phải thực hiện length = 2. Do đó, chúng ta có thể mã hóa cứng có nghĩa là hình học như root-root = sqrt (sqrt). Và chúng ta chỉ cần một hằng số FP , 4.0.

Chúng tôi có một vectơ SIMD duy nhất của cả 4 [a_i, b_i, c_i, d_i]. Từ đó, chúng tôi tính toán 4 phương tiện là vô hướng trong các thanh ghi riêng biệt và trộn chúng lại với nhau cho lần lặp tiếp theo. (Các thao tác ngang trên vectơ SIMD rất bất tiện, nhưng chúng tôi cần phải làm điều tương tự cho cả 4 yếu tố trong trường hợp đủ để nó cân bằng. Tôi đã bắt đầu phiên bản x87 này, nhưng nó rất dài và không vui.)

Điều kiện thoát vòng lặp của }while(quadratic - harmonic > 4e-5)(hoặc hằng số nhỏ hơn double) dựa trên câu trả lời R của @ RobinRydercâu trả lời Java của Kevin Cruijssen : trung bình bậc hai luôn có độ lớn nhất và trung bình hài luôn luôn là nhỏ nhất (bỏ qua các lỗi làm tròn). Vì vậy, chúng ta có thể kiểm tra delta giữa hai cái đó để phát hiện sự hội tụ. Chúng tôi trả về giá trị trung bình số học là kết quả vô hướng. Nó thường nằm giữa hai cái đó và có lẽ là ít dễ bị lỗi làm tròn nhất.

Phiên bản float : có thể gọi được như float meanmean_float_avx(__m128);với giá trị arg và return trong xmm0. (Vì vậy, x86-64 System V, hoặc Windows x64 vectorcall, nhưng không phải x64 fastcall.) Hoặc tuyên bố sự trở lại kiểu như __m128vậy bạn có thể có được tại giá trị trung bình toàn phương và hài hòa để thử nghiệm.

Để điều này mất 2 đối số riêng biệt floattrong xmm0 và xmm1 sẽ tốn thêm 1 byte: chúng ta cần một số shufps8 (thay vì chỉ unpcklps xmm0,xmm0) để trộn lẫn với nhau và sao chép 2 đầu vào.

    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

(Danh sách NASM được tạo bằng nasm -felf64 mean-mean.asm -l/dev/stdout | cut -b -34,$((34+6))-. Tách phần danh sách và khôi phục nguồn với cut -b 34- > mean-mean.asm)

Tổng số ngang SIMD và chia cho 4 (nghĩa là trung bình số học) được triển khai trong một hàm riêng mà chúng tôi call(với một con trỏ hàm để khấu hao chi phí của địa chỉ). Với 4/xtrước / sau, hoặc x^2trước và sqrt sau, chúng ta có được trung bình hài và trung bình bậc hai. (Thật đau đớn khi viết các divhướng dẫn này thay vì nhân với một đại diện chính xác 0.25.)

Trung bình hình học được thực hiện riêng với sqrt nhân và chuỗi. Hoặc với một sqrt đầu tiên để giảm cường độ lũy thừa và có thể giúp độ chính xác bằng số. Nhật ký không có sẵn, chỉ floor(log2(x))qua AVX512 vgetexpps/pd. Exp là loại có sẵn thông qua AVX512ER (chỉ Xeon Phi), nhưng chỉ với độ chính xác 2 ^ -23.

Trộn các hướng dẫn AVX 128 bit và SSE kế thừa không phải là vấn đề về hiệu năng. Việc trộn AVX 256 bit với SSE cũ có thể có trên Haswell, nhưng trên Skylake, nó chỉ có khả năng tạo ra sự phụ thuộc sai tiềm năng cho các hướng dẫn SSE. Tôi nghĩ rằng doublephiên bản của tôi tránh được bất kỳ chuỗi dep mang theo vòng lặp không cần thiết và tắc nghẽn về độ trễ / thông lượng div / sqrt.

Phiên bản đôi:

   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

Khai thác thử nghiệm 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);
        }
    }

}

Xây dựng với:

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

Rõ ràng bạn cần một CPU có hỗ trợ AVX hoặc trình giả lập như Intel SDE. Để biên dịch trên máy chủ mà không cần hỗ trợ AVX riêng, hãy sử dụng -march=sandybridgehoặc-mavx

Run: vượt qua các trường hợp kiểm thử được mã hóa cứng, nhưng đối với phiên bản float, các trường hợp kiểm tra ngẫu nhiên thường không đạt (b-a)/10000ngưỡng được đặt trong câu hỏi.

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

Lỗi FP là đủ để bốn tác hại xuất hiện dưới 0 đối với một số đầu vào.

Hoặc không có a += 1<<11; b += (1<<12)+1;dấu vết:

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

Không có vấn đề nào xảy ra với double. Nhận xét printftrước mỗi bài kiểm tra để thấy rằng đầu ra trống (không có gì từ if(delta too high)khối).

TODO: sử dụng doublephiên bản làm tài liệu tham khảo cho floatphiên bản, thay vì chỉ nhìn vào cách chúng hội tụ với tứ phương.


1

Javascript - 186 byte

Đưa đầu vào như một mảng số. Sử dụng các phép biến đổi trung bình trong câu trả lời của J42161217 để rút ngắn mã.

Dùng thử trực tuyến

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]

Giải trình

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

Tôi nghĩ rằng tôi sẽ thông minh và thực hiện mối quan hệ với logarit nhưng có vẻ như bạn và J42161217 đã đến đó trước!
Pureferret

@Pureferret Tôi sẽ không có tín dụng cho điều đó, tôi ngang nhiên lấy trộm nó: D
asgallant

bạn đã viết nó bằng JavaScript!
Pureferret

1
Đó là phần dễ dàng. Chơi golf thật khó.
asgallant

1
TIL không được cấu hình đúng. Tôi đã thêm một liên kết TIL cho câu trả lời.
ngày


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

Hãy thử trực tuyến!

Thực hiện đơn giản. Sử dụng một mẹo từ câu trả lời của tôi cho một câu hỏi liên quan đến golf nhiều hơn một chút.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.