Averages/Median: Difference between revisions
No edit summary |
RandomTask (talk | contribs) |
||
(349 intermediate revisions by more than 100 users not shown) | |||
Line 1: | Line 1: | ||
[[Category:Sorting]] |
|||
{{task|Probability and statistics}}Write a program to find the [[wp:Median|median]] value of a vector of floating-point numbers. The program need not handle the case where the vector is empty, but ''must'' handle the case where there are an even number of elements. |
|||
[[Category:E examples needing attention]] |
|||
{{task|Probability and statistics}} |
|||
;Task |
|||
There are several approaches to this. One is to sort the elements, and then pick the one in the middle. Sorting would take at least O(n log n). Another would be to build a priority queue from the elements, and then extract half of the elements to get to the middle one(s). This would also take O(n log n). The best solution is to use the [[wp:Selection algorithm|selection algorithm]] to find the median in O(n) time. |
|||
Write a program to find the [[wp:Median|median]] value of a vector of floating-point numbers. |
|||
The program need not handle the case where the vector is empty, but ''must'' handle the case where there are an even number of elements. In that case, return the average of the two middle values. |
|||
There are several approaches to this. One is to sort the elements, and then pick the element(s) in the middle. |
|||
Sorting would take at least <big><span style="font-family: serif">O(''n'' log''n'')</span></big>. Another approach would be to build a priority queue from the elements, and then extract half of the elements to get to the middle element(s). This would also take <big><span style="font-family: serif">O(''n'' log''n'')</span></big>. The best solution is to use the [[wp:Selection algorithm|selection algorithm]] to find the median in <big><span style="font-family: serif">O(''n'')</span></big> time. |
|||
{{task heading|See also}} |
|||
[[Quickselect_algorithm]] |
|||
{{Related tasks/Statistical measures}} |
|||
<hr> |
|||
=={{header|11l}}== |
|||
{{trans|Python}} |
|||
<syntaxhighlight lang="11l">F median(aray) |
|||
V srtd = sorted(aray) |
|||
V alen = srtd.len |
|||
R 0.5 * (srtd[(alen - 1) I/ 2] + srtd[alen I/ 2]) |
|||
print(median([4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2])) |
|||
print(median([4.1, 7.2, 1.7, 9.3, 4.4, 3.2]))</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
4.4 |
|||
4.25 |
|||
</pre> |
|||
=={{header|AArch64 Assembly}}== |
|||
{{works with|as|Raspberry Pi 3B version Buster 64 bits <br> or android 64 bits with application Termux }} |
|||
<syntaxhighlight lang AArch64 Assembly> |
|||
/* ARM assembly AARCH64 Raspberry PI 3B */ |
|||
/* program averageMed64.s */ |
|||
/* use quickselect look pseudo code in wikipedia quickselect */ |
|||
/************************************/ |
|||
/* Constantes */ |
|||
/************************************/ |
|||
/* for this file see task include a file in language AArch64 assembly*/ |
|||
.include "../includeConstantesARM64.inc" |
|||
/*********************************/ |
|||
/* Initialized data */ |
|||
/*********************************/ |
|||
.data |
|||
szMessResultValue: .asciz "Result : " |
|||
szCarriageReturn: .asciz "\n" |
|||
.align 4 |
|||
TableNumber: .double 4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2 |
|||
.equ NBELEMENTS, (. - TableNumber) / 8 |
|||
TableNumber2: .double 4.1, 7.2, 1.7, 9.3, 4.4, 3.2 |
|||
.equ NBELEMENTS2, (. - TableNumber2) / 8 |
|||
/*********************************/ |
|||
/* UnInitialized data */ |
|||
/*********************************/ |
|||
.bss |
|||
sZoneConv: .skip 24 |
|||
sZoneConv1: .skip 24 |
|||
/*********************************/ |
|||
/* code section */ |
|||
/*********************************/ |
|||
.text |
|||
.global main |
|||
main: // entry of program |
|||
ldr x0,qAdrTableNumber // address number table |
|||
mov x1,#0 // index first item |
|||
mov x2,#NBELEMENTS -1 // index last item |
|||
bl searchMedian |
|||
ldr x0,qAdrTableNumber2 // address number table 2 |
|||
mov x1,#0 // index first item |
|||
mov x2,#NBELEMENTS2 -1 // index last item |
|||
bl searchMedian |
|||
100: // standard end of the program |
|||
mov x0, #0 // return code |
|||
mov x8, #EXIT // request to exit program |
|||
svc #0 // perform the system call |
|||
qAdrszCarriageReturn: .quad szCarriageReturn |
|||
qAdrTableNumber: .quad TableNumber |
|||
qAdrTableNumber2: .quad TableNumber2 |
|||
qAdrsZoneConv: .quad sZoneConv |
|||
qAdrszMessResultValue: .quad szMessResultValue |
|||
/***************************************************/ |
|||
/* search median term in float array */ |
|||
/***************************************************/ |
|||
/* x0 contains the address of table */ |
|||
/* x1 contains index of first item */ |
|||
/* x2 contains index of last item */ |
|||
searchMedian: |
|||
stp x1,lr,[sp,-16]! // save registers TODO: à revoir génération |
|||
stp x2,x3,[sp,-16]! // save registers |
|||
stp x4,x5,[sp,-16]! // save registers |
|||
mov x19,x0 // save array address |
|||
add x4,x1,x2 |
|||
add x4,x4,#1 // sum numbers terms |
|||
tst x4,#1 // odd ? |
|||
bne 1f |
|||
lsr x3,x4,#1 // compute median index |
|||
bl select // call selection |
|||
fmov d0,x0 // save first result |
|||
sub x3,x3,#1 // second term |
|||
mov x0,x19 |
|||
bl select // call selection |
|||
fmov d1,x0 // save 2ieme résult |
|||
fadd d0,d0,d1 // compute average two résults |
|||
mov x0,#2 |
|||
fmov d1,x0 |
|||
scvtf d1,d1 // conversion integer -> float |
|||
fdiv d0,d0,d1 |
|||
b 2f |
|||
1: // even |
|||
lsr x3,x4,#1 |
|||
bl select // call selection |
|||
fmov d0,x0 |
|||
2: |
|||
ldr x0,qAdrsZoneConv // conversion float in decimal string |
|||
bl convertirFloat |
|||
mov x0,#3 // and display result |
|||
ldr x1,qAdrszMessResultValue |
|||
ldr x2,qAdrsZoneConv |
|||
ldr x3,qAdrszCarriageReturn |
|||
bl displayStrings |
|||
100: // end function |
|||
ldp x4,x5,[sp],16 // restaur 2 registers |
|||
ldp x2,x3,[sp],16 // restaur 2 registers |
|||
ldp x1,lr,[sp],16 // restaur 2 registers |
|||
ret |
|||
/***************************************************/ |
|||
/* Appel récursif selection */ |
|||
/***************************************************/ |
|||
/* x0 contains the address of table */ |
|||
/* x1 contains index of first item */ |
|||
/* x2 contains index of last item */ |
|||
/* x3 contains search index */ |
|||
select: |
|||
stp x1,lr,[sp,-16]! // save registers |
|||
stp x2,x3,[sp,-16]! // save registers |
|||
stp x4,x5,[sp,-16]! // save registers |
|||
stp x6,x7,[sp,-16]! // save registers |
|||
mov x6,x3 // save search index |
|||
cmp x1,x2 // first = last ? |
|||
bne 1f |
|||
ldr x0,[x0,x1,lsl #3] // return value of first index |
|||
b 100f // yes -> end |
|||
1: |
|||
add x3,x1,x2 |
|||
lsr x3,x3,#1 // compute median pivot |
|||
mov x4,x0 // save x0 |
|||
mov x5,x2 // save x2 |
|||
bl partition // cutting.quado 2 parts |
|||
cmp x6,x0 // pivot is ok ? |
|||
bne 2f |
|||
ldr x0,[x4,x0,lsl #3] // yes -> return value |
|||
b 100f |
|||
2: |
|||
bgt 3f |
|||
sub x2,x0,#1 // index partition - 1 |
|||
mov x0,x4 // array address |
|||
mov x3,x6 // search index |
|||
bl select // select lower part |
|||
b 100f |
|||
3: |
|||
add x1,x0,#1 // index begin = index partition + 1 |
|||
mov x0,x4 // array address |
|||
mov x2,x5 // last item |
|||
mov x3,x6 // search index |
|||
bl select // select higter part |
|||
100: // end function |
|||
ldp x6,x7,[sp],16 // restaur 2 registers |
|||
ldp x4,x5,[sp],16 // restaur 2 registers |
|||
ldp x2,x3,[sp],16 // restaur 2 registers |
|||
ldp x1,lr,[sp],16 // restaur 2 registers |
|||
ret // return to address lr x30 |
|||
/******************************************************************/ |
|||
/* Partition table elements */ |
|||
/******************************************************************/ |
|||
/* x0 contains the address of table */ |
|||
/* x1 contains index of first item */ |
|||
/* x2 contains index of last item */ |
|||
/* x3 contains index of pivot */ |
|||
partition: |
|||
stp x1,lr,[sp,-16]! // save registers |
|||
stp x2,x3,[sp,-16]! // save registers |
|||
stp x4,x5,[sp,-16]! // save registers |
|||
stp x6,x7,[sp,-16]! // save registers |
|||
ldr x4,[x0,x3,lsl #3] // load value of pivot |
|||
ldr x5,[x0,x2,lsl #3] // load value last index |
|||
str x5,[x0,x3,lsl #3] // swap value of pivot |
|||
str x4,[x0,x2,lsl #3] // and value last index |
|||
mov x3,x1 // init with first index |
|||
1: // begin loop |
|||
ldr x6,[x0,x3,lsl #3] // load value |
|||
cmp x6,x4 // compare loop value and pivot value |
|||
bge 2f |
|||
ldr x5,[x0,x1,lsl #3] // if < swap value table |
|||
str x6,[x0,x1,lsl #3] |
|||
str x5,[x0,x3,lsl #3] |
|||
add x1,x1,#1 // and increment index 1 |
|||
2: |
|||
add x3,x3,#1 // increment index 2 |
|||
cmp x3,x2 // end ? |
|||
blt 1b // no loop |
|||
ldr x5,[x0,x1,lsl #3] // swap value |
|||
str x4,[x0,x1,lsl #3] |
|||
str x5,[x0,x2,lsl #3] |
|||
mov x0,x1 // return index partition |
|||
100: |
|||
ldp x6,x7,[sp],16 // restaur 2 registers |
|||
ldp x4,x5,[sp],16 // restaur 2 registers |
|||
ldp x2,x3,[sp],16 // restaur 2 registers |
|||
ldp x1,lr,[sp],16 // restaur 2 registers |
|||
ret // return to address lr x30 |
|||
/***************************************************/ |
|||
/* display multi strings */ |
|||
/* new version 24/05/2023 */ |
|||
/***************************************************/ |
|||
/* x0 contains number strings address */ |
|||
/* x1 address string1 */ |
|||
/* x2 address string2 */ |
|||
/* x3 address string3 */ |
|||
/* x4 address string4 */ |
|||
/* x5 address string5 */ |
|||
/* x6 address string5 */ |
|||
/* x7 address string6 */ |
|||
displayStrings: // INFO: displayStrings |
|||
stp x8,lr,[sp,-16]! // save registers |
|||
stp x2,fp,[sp,-16]! // save registers |
|||
add fp,sp,#32 // save paraméters address (4 registers saved * 8 bytes) |
|||
mov x8,x0 // save strings number |
|||
cmp x8,#0 // 0 string -> end |
|||
ble 100f |
|||
mov x0,x1 // string 1 |
|||
bl affichageMess |
|||
cmp x8,#1 // number > 1 |
|||
ble 100f |
|||
mov x0,x2 |
|||
bl affichageMess |
|||
cmp x8,#2 |
|||
ble 100f |
|||
mov x0,x3 |
|||
bl affichageMess |
|||
cmp x8,#3 |
|||
ble 100f |
|||
mov x0,x4 |
|||
bl affichageMess |
|||
cmp x8,#4 |
|||
ble 100f |
|||
mov x0,x5 |
|||
bl affichageMess |
|||
cmp x8,#5 |
|||
ble 100f |
|||
mov x0,x6 |
|||
bl affichageMess |
|||
cmp x8,#6 |
|||
ble 100f |
|||
mov x0,x7 |
|||
bl affichageMess |
|||
100: |
|||
ldp x2,fp,[sp],16 // restaur registers |
|||
ldp x8,lr,[sp],16 // restaur registers |
|||
ret |
|||
/******************************************************************/ |
|||
/* Conversion Float */ |
|||
/******************************************************************/ |
|||
/* d0 contains Float */ |
|||
/* x0 contains address conversion area mini 20 charactèrs */ |
|||
/* x0 return result length */ |
|||
/* see https://blog.benoitblanchon.fr/lightweight-float-to-string/ */ |
|||
convertirFloat: |
|||
stp x1,lr,[sp,-16]! // save registres |
|||
stp x2,x3,[sp,-16]! // save registres |
|||
stp x4,x5,[sp,-16]! // save registres |
|||
stp x6,x7,[sp,-16]! // save registres |
|||
stp x8,x9,[sp,-16]! // save registres |
|||
stp d1,d2,[sp,-16]! // save registres |
|||
mov x6,x0 // save area address |
|||
fmov x0,d0 |
|||
mov x8,#0 // result length |
|||
mov x3,#'+' |
|||
strb w3,[x6] // signe + forcing |
|||
mov x2,x0 |
|||
tbz x2,63,1f |
|||
mov x2,1 |
|||
lsl x2,x2,63 |
|||
bic x0,x0,x2 |
|||
mov x3,#'-' // sign - |
|||
strb w3,[x6] |
|||
1: |
|||
adds x8,x8,#1 // next position |
|||
cmp x0,#0 // case 0 positive or negative |
|||
bne 2f |
|||
mov x3,#'0' |
|||
strb w3,[x6,x8] // store character 0 |
|||
adds x8,x8,#1 |
|||
strb wzr,[x6,x8] // store 0 final |
|||
mov x0,x8 // return length |
|||
b 100f |
|||
2: |
|||
ldr x2,iMaskExposant |
|||
mov x1,x0 |
|||
and x1,x1,x2 // exposant |
|||
cmp x1,x2 |
|||
bne 4f |
|||
tbz x0,51,3f // test bit 51 to zéro |
|||
mov x2,#'N' // case Nan. store byte no possible store integer |
|||
strb w2,[x6] // area no aligned |
|||
mov x2,#'a' |
|||
strb w2,[x6,#1] |
|||
mov x2,#'n' |
|||
strb w2,[x6,#2] |
|||
mov x2,#0 // 0 final |
|||
strb w2,[x6,#3] |
|||
mov x0,#3 |
|||
b 100f |
|||
3: // case infini positive or négative |
|||
mov x2,#'I' |
|||
strb w2,[x6,x8] |
|||
adds x8,x8,#1 |
|||
mov x2,#'n' |
|||
strb w2,[x6,x8] |
|||
adds x8,x8,#1 |
|||
mov x2,#'f' |
|||
strb w2,[x6,x8] |
|||
adds x8,x8,#1 |
|||
mov x2,#0 |
|||
strb w2,[x6,x8] |
|||
mov x0,x8 |
|||
b 100f |
|||
4: |
|||
bl normaliserFloat |
|||
mov x5,x0 // save exposant |
|||
fcvtzu d2,d0 |
|||
fmov x0,d2 // part integer |
|||
scvtf d1,d2 // conversion float |
|||
fsub d1,d0,d1 // extraction part fractional |
|||
ldr d2,dConst1 |
|||
fmul d1,d2,d1 // to crop it in full |
|||
fcvtzu d1,d1 // convertion integer |
|||
fmov x4,d1 // fract value |
|||
// conversion part integer to x0 |
|||
mov x2,x6 // save address begin area |
|||
adds x6,x6,x8 |
|||
mov x1,x6 |
|||
bl conversion10 |
|||
add x6,x6,x0 |
|||
mov x3,#',' |
|||
strb w3,[x6] |
|||
adds x6,x6,#1 |
|||
mov x0,x4 // conversion part fractionnaire |
|||
mov x1,x6 |
|||
bl conversion10SP |
|||
add x6,x6,x0 |
|||
sub x6,x6,#1 |
|||
// remove trailing zeros |
|||
5: |
|||
ldrb w0,[x6] |
|||
cmp w0,#'0' |
|||
bne 6f |
|||
sub x6,x6,#1 |
|||
b 5b |
|||
6: |
|||
cmp w0,#',' |
|||
bne 7f |
|||
sub x6,x6,#1 |
|||
7: |
|||
cmp x5,#0 // if exposant = 0 no display |
|||
bne 8f |
|||
add x6,x6,#1 |
|||
b 10f |
|||
8: |
|||
add x6,x6,#1 |
|||
mov x3,#'E' |
|||
strb w3,[x6] |
|||
add x6,x6,#1 |
|||
mov x0,x5 // conversion exposant |
|||
mov x3,x0 |
|||
tbz x3,63,9f // exposant negative ? |
|||
neg x0,x0 |
|||
mov x3,#'-' |
|||
strb w3,[x6] |
|||
adds x6,x6,#1 |
|||
9: |
|||
mov x1,x6 |
|||
bl conversion10 |
|||
add x6,x6,x0 |
|||
10: |
|||
strb wzr,[x6] // store 0 final |
|||
adds x6,x6,#1 |
|||
mov x0,x6 |
|||
subs x0,x0,x2 // retour de la longueur de la zone |
|||
subs x0,x0,#1 // sans le 0 final |
|||
100: |
|||
ldp d1,d2,[sp],16 // restaur registres |
|||
ldp x8,x9,[sp],16 // restaur registres |
|||
ldp x6,x7,[sp],16 // restaur registres |
|||
ldp x4,x5,[sp],16 // restaur registres |
|||
ldp x2,x3,[sp],16 // restaur registres |
|||
ldp x1,lr,[sp],16 // restaur registres |
|||
ret |
|||
iMaskExposant: .quad 0x7FF<<52 |
|||
dConst1: .double 0f1E17 |
|||
/***************************************************/ |
|||
/* normaliser float */ |
|||
/***************************************************/ |
|||
/* x0 contain float value (always positive value and <> Nan) */ |
|||
/* d0 return new value */ |
|||
/* x0 return exposant */ |
|||
normaliserFloat: |
|||
stp x1,lr,[sp,-16]! // save registers |
|||
fmov d0,x0 // value float |
|||
mov x0,#0 // exposant |
|||
ldr d1,dConstE7 // no normalisation for value < 1E7 |
|||
fcmp d0,d1 |
|||
blo 10f // if d0 < dConstE7 |
|||
ldr d1,dConstE256 |
|||
fcmp d0,d1 |
|||
blo 1f |
|||
fdiv d0,d0,d1 |
|||
adds x0,x0,#256 |
|||
1: |
|||
ldr d1,dConstE128 |
|||
fcmp d0,d1 |
|||
blo 1f |
|||
fdiv d0,d0,d1 |
|||
adds x0,x0,#128 |
|||
1: |
|||
ldr d1,dConstE64 |
|||
fcmp d0,d1 |
|||
blo 1f |
|||
fdiv d0,d0,d1 |
|||
adds x0,x0,#64 |
|||
1: |
|||
ldr d1,dConstE32 |
|||
fcmp d0,d1 |
|||
blo 1f |
|||
fdiv d0,d0,d1 |
|||
adds x0,x0,#32 |
|||
1: |
|||
ldr d1,dConstE16 |
|||
fcmp d0,d1 |
|||
blo 2f |
|||
fdiv d0,d0,d1 |
|||
adds x0,x0,#16 |
|||
2: |
|||
ldr d1,dConstE8 |
|||
fcmp d0,d1 |
|||
blo 3f |
|||
fdiv d0,d0,d1 |
|||
adds x0,x0,#8 |
|||
3: |
|||
ldr d1,dConstE4 |
|||
fcmp d0,d1 |
|||
blo 4f |
|||
fdiv d0,d0,d1 |
|||
adds x0,x0,#4 |
|||
4: |
|||
ldr d1,dConstE2 |
|||
fcmp d0,d1 |
|||
blo 5f |
|||
fdiv d0,d0,d1 |
|||
adds x0,x0,#2 |
|||
5: |
|||
ldr d1,dConstE1 |
|||
fcmp d0,d1 |
|||
blo 10f |
|||
fdiv d0,d0,d1 |
|||
adds x0,x0,#1 |
|||
10: |
|||
ldr d1,dConstME5 // pas de normalisation pour les valeurs > 1E-5 |
|||
fcmp d0,d1 |
|||
bhi 100f // fin |
|||
ldr d1,dConstME255 |
|||
fcmp d0,d1 |
|||
bhi 11f |
|||
ldr d1,dConstE256 |
|||
fmul d0,d0,d1 |
|||
subs x0,x0,#256 |
|||
11: |
|||
ldr d1,dConstME127 |
|||
fcmp d0,d1 |
|||
bhi 11f |
|||
ldr d1,dConstE128 |
|||
fmul d0,d0,d1 |
|||
subs x0,x0,#128 |
|||
11: |
|||
ldr d1,dConstME63 |
|||
fcmp d0,d1 |
|||
bhi 11f |
|||
ldr d1,dConstE64 |
|||
fmul d0,d0,d1 |
|||
subs x0,x0,#64 |
|||
11: |
|||
ldr d1,dConstME31 |
|||
fcmp d0,d1 |
|||
bhi 11f |
|||
ldr d1,dConstE32 |
|||
fmul d0,d0,d1 |
|||
subs x0,x0,#32 |
|||
11: |
|||
ldr d1,dConstME15 |
|||
fcmp d0,d1 |
|||
bhi 12f |
|||
ldr d1,dConstE16 |
|||
fmul d0,d0,d1 |
|||
subs x0,x0,#16 |
|||
12: |
|||
ldr d1,dConstME7 |
|||
fcmp d0,d1 |
|||
bhi 13f |
|||
ldr d1,dConstE8 |
|||
fmul d0,d0,d1 |
|||
subs x0,x0,#8 |
|||
13: |
|||
ldr d1,dConstME3 |
|||
fcmp d0,d1 |
|||
bhi 14f |
|||
ldr d1,dConstE4 |
|||
fmul d0,d0,d1 |
|||
subs x0,x0,#4 |
|||
14: |
|||
ldr d1,dConstME1 |
|||
fcmp d0,d1 |
|||
bhi 15f |
|||
ldr d1,dConstE2 |
|||
fmul d0,d0,d1 |
|||
subs x0,x0,#2 |
|||
15: |
|||
ldr d1,dConstE0 |
|||
fcmp d0,d1 |
|||
bhi 100f |
|||
ldr d1,dConstE1 |
|||
fmul d0,d0,d1 |
|||
subs x0,x0,#1 |
|||
100: // fin standard de la fonction |
|||
ldp x1,lr,[sp],16 // restaur registres |
|||
ret |
|||
.align 2 |
|||
dConstE7: .double 0f1E7 |
|||
dConstE256: .double 0f1E256 |
|||
dConstE128: .double 0f1E128 |
|||
dConstE64: .double 0f1E64 |
|||
dConstE32: .double 0f1E32 |
|||
dConstE16: .double 0f1E16 |
|||
dConstE8: .double 0f1E8 |
|||
dConstE4: .double 0f1E4 |
|||
dConstE2: .double 0f1E2 |
|||
dConstE1: .double 0f1E1 |
|||
dConstME5: .double 0f1E-5 |
|||
dConstME255: .double 0f1E-255 |
|||
dConstME127: .double 0f1E-127 |
|||
dConstME63: .double 0f1E-63 |
|||
dConstME31: .double 0f1E-31 |
|||
dConstME15: .double 0f1E-15 |
|||
dConstME7: .double 0f1E-7 |
|||
dConstME3: .double 0f1E-3 |
|||
dConstME1: .double 0f1E-1 |
|||
dConstE0: .double 0f1E0 |
|||
/******************************************************************/ |
|||
/* Décimal Conversion */ |
|||
/******************************************************************/ |
|||
/* x0 contain value et x1 address conversion area */ |
|||
conversion10SP: |
|||
stp x1,lr,[sp,-16]! // save registers |
|||
stp x2,x3,[sp,-16]! // save registers |
|||
stp x4,x5,[sp,-16]! // save registers |
|||
mov x5,x1 |
|||
mov x4,#16 |
|||
mov x2,x0 |
|||
mov x1,#10 // décimal conversion |
|||
1: // conversion loop |
|||
mov x0,x2 // copy begin number or quotient |
|||
udiv x2,x0,x1 // division by 10 |
|||
msub x3,x1,x2,x0 // compute remainder |
|||
add x3,x3,#48 // compute digit |
|||
strb w3,[x5,x4] // store byte address area (x5) + offset (x4) |
|||
subs x4,x4,#1 // position precedente |
|||
bge 1b |
|||
strb wzr,[x5,16] // 0 final |
|||
100: |
|||
ldp x4,x5,[sp],16 // restaur registers |
|||
ldp x2,x3,[sp],16 // restaur registers |
|||
ldp x1,lr,[sp],16 // restaur registers |
|||
ret |
|||
/***************************************************/ |
|||
/* ROUTINES INCLUDE */ |
|||
/***************************************************/ |
|||
/* for this file see task include a file in language AArch64 assembly*/ |
|||
.include "../includeARM64.inc" |
|||
</syntaxhighlight> |
|||
{{Out}} |
|||
<pre> |
|||
Result : +4,4 |
|||
Result : +4,25 |
|||
</pre> |
|||
=={{header|Action!}}== |
|||
{{libheader|Action! Tool Kit}} |
|||
{{libheader|Action! Real Math}} |
|||
<syntaxhighlight lang="action!">INCLUDE "H6:REALMATH.ACT" |
|||
DEFINE PTR="CARD" |
|||
PROC Sort(PTR ARRAY a INT count) |
|||
INT i,j,minpos |
|||
REAL POINTER tmp |
|||
FOR i=0 TO count-2 |
|||
DO |
|||
minpos=i |
|||
FOR j=i+1 TO count-1 |
|||
DO |
|||
IF RealGreaterOrEqual(a(minpos),a(j)) THEN |
|||
minpos=j |
|||
FI |
|||
OD |
|||
IF minpos#i THEN |
|||
tmp=a(i) |
|||
a(i)=a(minpos) |
|||
a(minpos)=tmp |
|||
FI |
|||
OD |
|||
RETURN |
|||
PROC Median(PTR ARRAY a INT count REAL POINTER res) |
|||
IF count=0 THEN Break() FI |
|||
Sort(a,count) |
|||
IF (count&1)=0 THEN |
|||
RealAdd(a(count RSH 1-1),a(count RSH 1),res) |
|||
RealMult(res,half,res) |
|||
ELSE |
|||
RealAssign(a(count RSH 1),res) |
|||
FI |
|||
RETURN |
|||
PROC Test(PTR ARRAY a INT count) |
|||
INT i |
|||
REAL res |
|||
FOR i=0 TO count-1 |
|||
DO |
|||
PrintR(a(i)) Put(32) |
|||
OD |
|||
Median(a,count,res) |
|||
Print("-> ") |
|||
PrintRE(res) |
|||
RETURN |
|||
PROC Main() |
|||
PTR ARRAY a(8) |
|||
REAL r1,r2,r3,r4,r5,r6,r7,r8 |
|||
BYTE i |
|||
Put(125) PutE() ;clear the screen |
|||
MathInit() |
|||
ValR("3.2",r1) ValR("-4.1",r2) |
|||
ValR("0.6",r3) ValR("9.8",r4) |
|||
ValR("5.1",r5) ValR("-1.4",r6) |
|||
ValR("0.3",r7) ValR("2.2",r8) |
|||
FOR i=1 TO 8 |
|||
DO |
|||
a(0)=r1 a(1)=r2 a(2)=r3 a(3)=r4 |
|||
a(4)=r5 a(5)=r6 a(6)=r7 a(7)=r8 |
|||
Test(a,i) |
|||
OD |
|||
RETURN</syntaxhighlight> |
|||
{{out}} |
|||
[https://gitlab.com/amarok8bit/action-rosetta-code/-/raw/master/images/Averages_Median.png Screenshot from Atari 8-bit computer] |
|||
<pre> |
|||
3.2 -> 3.2 |
|||
3.2 -4.1 -> -0.45 |
|||
3.2 -4.1 .6 -> .6 |
|||
3.2 -4.1 .6 9.8 -> 1.9 |
|||
3.2 -4.1 .6 9.8 5.1 -> 3.2 |
|||
3.2 -4.1 .6 9.8 5.1 -1.4 -> 1.9 |
|||
3.2 -4.1 .6 9.8 5.1 -1.4 .3 -> .6 |
|||
3.2 -4.1 .6 9.8 5.1 -1.4 .3 2.2 -> 1.4 |
|||
</pre> |
|||
=={{header|Ada}}== |
|||
<syntaxhighlight lang="ada">with Ada.Text_IO, Ada.Float_Text_IO; |
|||
procedure FindMedian is |
|||
f: array(1..10) of float := ( 4.4, 2.3, -1.7, 7.5, 6.6, 0.0, 1.9, 8.2, 9.3, 4.5 ); |
|||
min_idx: integer; |
|||
min_val, median_val, swap: float; |
|||
begin |
|||
for i in f'range loop |
|||
min_idx := i; |
|||
min_val := f(i); |
|||
for j in i+1 .. f'last loop |
|||
if f(j) < min_val then |
|||
min_idx := j; |
|||
min_val := f(j); |
|||
end if; |
|||
end loop; |
|||
swap := f(i); f(i) := f(min_idx); f(min_idx) := swap; |
|||
end loop; |
|||
if f'length mod 2 /= 0 then |
|||
median_val := f( f'length/2+1 ); |
|||
else |
|||
median_val := ( f(f'length/2) + f(f'length/2+1) ) / 2.0; |
|||
end if; |
|||
Ada.Text_IO.Put( "Median value: " ); |
|||
Ada.Float_Text_IO.Put( median_val ); |
|||
Ada.Text_IO.New_line; |
|||
end FindMedian;</syntaxhighlight> |
|||
=={{header|ALGOL 68}}== |
|||
{{trans|C}}<syntaxhighlight lang="algol68">INT max_elements = 1000000; |
|||
# Return the k-th smallest item in array x of length len # |
|||
PROC quick_select = (INT k, REF[]REAL x) REAL: |
|||
BEGIN |
|||
PROC swap = (INT a, b) VOID: |
|||
BEGIN |
|||
REAL t = x[a]; |
|||
x[a] := x[b]; x[b] := t |
|||
END; |
|||
INT left := 1, right := UPB x; |
|||
INT pos, i; |
|||
REAL pivot; |
|||
WHILE left < right DO |
|||
pivot := x[k]; |
|||
swap (k, right); |
|||
pos := left; |
|||
FOR i FROM left TO right DO |
|||
IF x[i] < pivot THEN |
|||
swap (i, pos); |
|||
pos +:= 1 |
|||
FI |
|||
OD; |
|||
swap (right, pos); |
|||
IF pos = k THEN break FI; |
|||
IF pos < k THEN left := pos + 1 |
|||
ELSE right := pos - 1 |
|||
FI |
|||
OD; |
|||
break: |
|||
SKIP; |
|||
x[k] |
|||
END; |
|||
# Initialize random length REAL array with random doubles # |
|||
INT length = ENTIER (next random * max_elements); |
|||
[length]REAL x; |
|||
FOR i TO length DO |
|||
x[i] := (next random * 1e6 - 0.5e6) |
|||
OD; |
|||
REAL median := |
|||
IF NOT ODD length THEN |
|||
# Even number of elements, median is average of middle two # |
|||
(quick_select (length % 2, x) + quick_select(length % 2 - 1, x)) / 2 |
|||
ELSE |
|||
# select middle element # |
|||
quick_select(length % 2, x) |
|||
FI; |
|||
# Sanity testing of median # |
|||
INT less := 0, more := 0, eq := 0; |
|||
FOR i TO length DO |
|||
IF x[i] < median THEN less +:= 1 |
|||
ELIF x[i] > median THEN more +:= 1 |
|||
ELSE eq +:= 1 |
|||
FI |
|||
OD; |
|||
print (("length: ", whole (length,0), new line, "median: ", median, new line, |
|||
"<: ", whole (less,0), new line, |
|||
">: ", whole (more, 0), new line, |
|||
"=: ", whole (eq, 0), new line))</syntaxhighlight> |
|||
Sample output: |
|||
<pre>length: 97738 |
|||
median: -2.52550126608709e +3 |
|||
<: 48868 |
|||
>: 48870 |
|||
=: 0 |
|||
</pre> |
|||
=={{header|Amazing Hopper}}== |
|||
{{trans|BaCon}}<syntaxhighlight lang="c"> |
|||
#include <basico.h> |
|||
#proto cálculodemediana(_X_) |
|||
#synon _cálculodemediana obtenermedianade |
|||
algoritmo |
|||
decimales '2' |
|||
matrices 'a,b' |
|||
'4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2', enlistar en 'a' |
|||
'4.1, 7.2, 1.7, 9.3, 4.4, 3.2', enlistar en 'b' |
|||
arr.ordenar 'a' |
|||
arr.ordenar 'b' |
|||
"A=",a,NL,"Median: ", obtener mediana de 'a', NL |
|||
"B=",b,NL,"Median: ", obtener mediana de 'b', NL |
|||
finalmente imprime |
|||
terminar |
|||
subrutinas |
|||
cálculo de mediana (x) |
|||
dx=0 |
|||
filas de 'x' ---copiar en 'dx'--- |
|||
calcular si ( es par?, #( (x[ (dx/2) ]+x[ (dx/2)+1 ])/2 ),\ |
|||
#( x[ dx/2+1 ] ) ) |
|||
retornar |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
A=1.70,3.20,4.10,4.40,5.60,7.20,9.30 |
|||
Median: 4.40 |
|||
B=1.70,3.20,4.10,4.40,7.20,9.30 |
|||
Median: 4.25 |
|||
</pre> |
|||
=={{header|AntLang}}== |
|||
AntLang has a built-in median function. |
|||
<syntaxhighlight lang="antlang">median[list]</syntaxhighlight> |
|||
=={{header|APL}}== |
|||
<syntaxhighlight lang="apl">median←{v←⍵[⍋⍵]⋄.5×v[⌈¯1+.5×⍴v]+v[⌊.5×⍴v]} ⍝ Assumes ⎕IO←0</syntaxhighlight> |
|||
First, the input vector ⍵ is sorted with ⍵[⍋⍵] and the result placed in v. If the dimension ⍴v of v is odd, then both ⌈¯1+.5×⍴v and ⌊.5×⍴v give the index of the middle element. If ⍴v is even, ⌈¯1+.5×⍴v and ⌊.5×⍴v give the indices of the two middle-most elements. In either case, the average of the elements at these indices gives the median. |
|||
Note that the index origin ⎕IO is assumed zero. To set it to zero use: <syntaxhighlight lang="apl">⎕IO←0</syntaxhighlight> |
|||
If you prefer an index origin of 1, use this code instead: |
|||
<syntaxhighlight lang="apl"> |
|||
⎕IO←1 |
|||
median←{v←⍵[⍋⍵] ⋄ 0.5×v[⌈0.5×⍴v]+v[⌊1+0.5×⍴v]} |
|||
</syntaxhighlight> |
|||
This code was tested with ngn/apl and Dyalog 12.1. You can try this function online with [http://ngn.github.io/apl/web/index.html#code=median%u2190%7Bv%u2190%u2375%5B%u234B%u2375%5D%u22C4.5%D7v%5B%u2308%AF1+.5%D7%u2374v%5D+v%5B%u230A.5%D7%u2374v%5D%7D ngn/apl]. Note that ngn/apl currently only supports index origin 0. Examples: |
|||
<pre>median 1 5 3 6 4 2 |
|||
3.5 |
|||
median 1 5 3 2 4 |
|||
3 |
|||
median 4.4 2.3 ¯1.7 7.5 6.6 0.0 1.9 8.2 9.3 4.5 |
|||
4.45 |
|||
median 4.1 4 1.2 6.235 7868.33 |
|||
4.1 |
|||
median 4.1 5.6 7.2 1.7 9.3 4.4 3.2 |
|||
4.4 |
|||
median 4.1 7.2 1.7 9.3 4.4 3.2 |
|||
4.25</pre> |
|||
Caveats: To keep it simple, no input validation is done. If you input a vector with zero elements (e.g., ⍳0), you get an INDEX ERROR. If you input a vector with 1 element, you get a RANK ERROR. Only (rank 1) numeric vectors of dimension 2 or more are supported. If you input a (rank 2 or more) matrix, you get a RANK ERROR. If you input a string (vector of chars), you get a DOMAIN ERROR: |
|||
<pre>median ⍳0 |
|||
INDEX ERROR |
|||
median 66.6 |
|||
RANK ERROR |
|||
median (2 2)⍴⍳4 ⍝ 2x2 matrix |
|||
RANK ERROR |
|||
median 'HELLO' |
|||
DOMAIN ERROR</pre> |
|||
=={{header|AppleScript}}== |
|||
===By iteration=== |
|||
<syntaxhighlight lang="applescript">set alist to {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0} |
|||
set med to medi(alist) |
|||
on medi(alist) |
|||
set temp to {} |
|||
set lcount to count alist |
|||
if lcount is equal to 2 then |
|||
return ((item 1 of alist) + (item 2 of alist)) / 2 |
|||
else if lcount is less than 2 then |
|||
return item 1 of alist |
|||
else --if lcount is greater than 2 |
|||
set min to findmin(alist) |
|||
set max to findmax(alist) |
|||
repeat with x from 1 to lcount |
|||
if x is not equal to min and x is not equal to max then set end of temp to item x of alist |
|||
end repeat |
|||
set med to medi(temp) |
|||
end if |
|||
return med |
|||
end medi |
|||
on findmin(alist) |
|||
set min to 1 |
|||
set alength to count every item of alist |
|||
repeat with x from 1 to alength |
|||
if item x of alist is less than item min of alist then set min to x |
|||
end repeat |
|||
return min |
|||
end findmin |
|||
on findmax(alist) |
|||
set max to 1 |
|||
set alength to count every item of alist |
|||
repeat with x from 1 to alength |
|||
if item x of alist is greater than item max of alist then set max to x |
|||
end repeat |
|||
return max |
|||
end findmax</syntaxhighlight> |
|||
{{output}} |
|||
<syntaxhighlight lang="applescript">4.5</syntaxhighlight> |
|||
===Composing functionally=== |
|||
Using a quick select algorithm: |
|||
{{Trans|JavaScript}} |
|||
{{Trans|Haskell}} |
|||
<syntaxhighlight lang="applescript">-- MEDIAN --------------------------------------------------------------------- |
|||
-- median :: [Num] -> Num |
|||
on median(xs) |
|||
-- nth :: [Num] -> Int -> Maybe Num |
|||
script nth |
|||
on |λ|(xxs, n) |
|||
if length of xxs > 0 then |
|||
set {x, xs} to uncons(xxs) |
|||
script belowX |
|||
on |λ|(y) |
|||
y < x |
|||
end |λ| |
|||
end script |
|||
set {ys, zs} to partition(belowX, xs) |
|||
set k to length of ys |
|||
if k = n then |
|||
x |
|||
else |
|||
if k > n then |
|||
|λ|(ys, n) |
|||
else |
|||
|λ|(zs, n - k - 1) |
|||
end if |
|||
end if |
|||
else |
|||
missing value |
|||
end if |
|||
end |λ| |
|||
end script |
|||
set n to length of xs |
|||
if n > 0 then |
|||
tell nth |
|||
if n mod 2 = 0 then |
|||
(|λ|(xs, n div 2) + |λ|(xs, (n div 2) - 1)) / 2 |
|||
else |
|||
|λ|(xs, n div 2) |
|||
end if |
|||
end tell |
|||
else |
|||
missing value |
|||
end if |
|||
end median |
|||
-- TEST ----------------------------------------------------------------------- |
|||
on run |
|||
map(median, [¬ |
|||
[], ¬ |
|||
[5, 3, 4], ¬ |
|||
[5, 4, 2, 3], ¬ |
|||
[3, 4, 1, -8.4, 7.2, 4, 1, 1.2]]) |
|||
--> {missing value, 4, 3.5, 2.1} |
|||
end run |
|||
-- GENERIC FUNCTIONS ---------------------------------------------------------- |
|||
-- map :: (a -> b) -> [a] -> [b] |
|||
on map(f, xs) |
|||
tell mReturn(f) |
|||
set lng to length of xs |
|||
set lst to {} |
|||
repeat with i from 1 to lng |
|||
set end of lst to |λ|(item i of xs, i, xs) |
|||
end repeat |
|||
return lst |
|||
end tell |
|||
end map |
|||
-- Lift 2nd class handler function into 1st class script wrapper |
|||
-- mReturn :: Handler -> Script |
|||
on mReturn(f) |
|||
if class of f is script then |
|||
f |
|||
else |
|||
script |
|||
property |λ| : f |
|||
end script |
|||
end if |
|||
end mReturn |
|||
-- partition :: predicate -> List -> (Matches, nonMatches) |
|||
-- partition :: (a -> Bool) -> [a] -> ([a], [a]) |
|||
on partition(f, xs) |
|||
tell mReturn(f) |
|||
set lst to {{}, {}} |
|||
repeat with x in xs |
|||
set v to contents of x |
|||
set end of item ((|λ|(v) as integer) + 1) of lst to v |
|||
end repeat |
|||
end tell |
|||
{item 2 of lst, item 1 of lst} |
|||
end partition |
|||
-- uncons :: [a] -> Maybe (a, [a]) |
|||
on uncons(xs) |
|||
if length of xs > 0 then |
|||
{item 1 of xs, rest of xs} |
|||
else |
|||
missing value |
|||
end if |
|||
end uncons</syntaxhighlight> |
|||
{{Out}} |
|||
<syntaxhighlight lang="applescript">{missing value, 4, 3.5, 2.1}</syntaxhighlight> |
|||
---- |
|||
===Quickselect=== |
|||
<syntaxhighlight lang="applescript">-- Return the median value of items l thru r of a list of numbers. |
|||
on getMedian(theList, l, r) |
|||
if (theList is {}) then return theList |
|||
script o |
|||
property lst : theList's items l thru r -- Copy of the range to be searched. |
|||
end script |
|||
set rangeLength to (r - l + 1) |
|||
set m to (rangeLength + 1) div 2 -- Central position in the range copy, or the leftmost of two. |
|||
set {l, r} to {1, rangeLength} -- Outer partition indices. |
|||
set previousR to r -- Reminder of previous r. |
|||
repeat -- quickselect repeat |
|||
set pivot to o's lst's item ((l + r) div 2) |
|||
set i to l |
|||
set j to r |
|||
repeat until (i > j) |
|||
set lv to o's lst's item i |
|||
repeat while (lv < pivot) |
|||
set i to i + 1 |
|||
set lv to o's lst's item i |
|||
end repeat |
|||
set rv to o's lst's item j |
|||
repeat while (rv > pivot) |
|||
set j to j - 1 |
|||
set rv to o's lst's item j |
|||
end repeat |
|||
if (i > j) then |
|||
else |
|||
set o's lst's item i to rv |
|||
set o's lst's item j to lv |
|||
set i to i + 1 |
|||
set j to j - 1 |
|||
end if |
|||
end repeat |
|||
-- If i and j have crossed at m, item m's the median value. |
|||
-- Otherwise reset to partition the partition containing m. |
|||
if (j < m) then |
|||
if (i > m) then exit repeat |
|||
set l to i |
|||
else |
|||
set previousR to r |
|||
set r to j |
|||
end if |
|||
end repeat |
|||
set median to item m of o's lst |
|||
-- If the range has an even number of items, find the lowest value to the right of m and average it |
|||
-- with the median just obtained. We only need to search to the end of the range just partitioned — |
|||
-- unless that's where m is, in which case to end of the most recent extent beyond that (if any). |
|||
if (rangeLength mod 2 is 0) then |
|||
set median2 to item i of o's lst |
|||
if (r = m) then set r to previousR |
|||
repeat with i from (i + 1) to r |
|||
set v to item i of o's lst |
|||
if (v < median2) then set median2 to v |
|||
end repeat |
|||
set median to (median + median2) / 2 |
|||
end if |
|||
return median |
|||
end getMedian |
|||
-- Demo: |
|||
local testList |
|||
set testList to {} |
|||
repeat with i from 1 to 8 |
|||
set end of testList to (random number 500) / 5 |
|||
end repeat |
|||
return {|numbers|:testList, median:getMedian(testList, 1, (count testList))}</syntaxhighlight> |
|||
{{output}} |
|||
<pre>{|numbers|:{71.6, 44.8, 45.8, 28.6, 96.8, 98.4, 42.4, 97.8}, median:58.7}</pre> |
|||
===Partial heap sort=== |
|||
<syntaxhighlight lang="applescript">-- Based on the heap sort algorithm ny J.W.J. Williams. |
|||
on getMedian(theList, l, r) |
|||
script o |
|||
property lst : theList's items l thru r -- Copy of the range to be searched. |
|||
-- Sift a value down into the heap from a given root node. |
|||
on siftDown(siftV, root, endOfHeap) |
|||
set child to root * 2 |
|||
repeat until (child comes after endOfHeap) |
|||
set childV to item child of my lst |
|||
if (child comes before endOfHeap) then |
|||
set child2 to child + 1 |
|||
set child2V to item child2 of my lst |
|||
if (child2V > childV) then |
|||
set child to child2 |
|||
set childV to child2V |
|||
end if |
|||
end if |
|||
if (childV > siftV) then |
|||
set item root of my lst to childV |
|||
set root to child |
|||
set child to root * 2 |
|||
else |
|||
exit repeat |
|||
end if |
|||
end repeat |
|||
set item root of my lst to siftV |
|||
end siftDown |
|||
end script |
|||
set r to (r - l + 1) |
|||
-- Arrange the sort range into a "heap" with its "top" at the leftmost position. |
|||
repeat with i from (r + 1) div 2 to 1 by -1 |
|||
tell o to siftDown(item i of its lst, i, r) |
|||
end repeat |
|||
-- Work the heap as if extracting the values that would come after the median when sorted. |
|||
repeat with endOfHeap from r to (r - (r + 1) div 2 + 2) by -1 |
|||
tell o to siftDown(item endOfHeap of its lst, 1, endOfHeap - 1) |
|||
end repeat |
|||
-- Extract the median itself, now at the top of the heap. |
|||
set median to beginning of o's lst |
|||
-- If the range has an even number of items, also get the value that would come before the median |
|||
-- just obtained. By now it's either the second or third item in the heap, so no need to sift for it. |
|||
-- Get the average if it and the median. |
|||
if (r mod 2 is 0) then |
|||
set median2 to item 2 of o's lst |
|||
if ((r > 2) and (item 3 of o's lst > median2)) then set median2 to item 3 of o's lst |
|||
set median to (median + median2) / 2 |
|||
end if |
|||
return median |
|||
end getMedian |
|||
-- Demo: |
|||
local testList |
|||
set testList to {} |
|||
repeat with i from 1 to 8 |
|||
set end of testList to (random number 500) / 5 |
|||
end repeat |
|||
return {|numbers|:testList, median:getMedian(testList, 1, (count testList))} |
|||
</syntaxhighlight> |
|||
{{output}} |
|||
<syntaxhighlight lang="applescript">{|numbers|:{28.0, 75.6, 21.4, 51.8, 79.6, 25.0, 95.4, 31.2}, median:41.5}</syntaxhighlight> |
|||
=={{header|Applesoft BASIC}}== |
|||
<syntaxhighlight lang="applesoft basic"> 100 REMMEDIAN |
|||
110 K = INT(L/2) : GOSUB 150 |
|||
120 R = X(K) |
|||
130 IF L - 2 * INT (L / 2) THEN R = (R + X(K + 1)) / 2 |
|||
140 RETURN |
|||
150 REMQUICK SELECT |
|||
160 LT = 0:RT = L - 1 |
|||
170 FOR J = LT TO RT STEP 0 |
|||
180 PT = X(K) |
|||
190 P1 = K:P2 = RT: GOSUB 300 |
|||
200 P = LT |
|||
210 FOR I = P TO RT - 1 |
|||
220 IF X(I) < PT THEN P1 = I:P2 = P: GOSUB 300:P = P + 1 |
|||
230 NEXT I |
|||
240 P1 = RT:P2 = P: GOSUB 300 |
|||
250 IF P = K THEN RETURN |
|||
260 IF P < K THEN LT = P + 1 |
|||
270 IF P > = K THEN RT = P - 1 |
|||
280 NEXT J |
|||
290 RETURN |
|||
300 REMSWAP |
|||
310 H = X(P1):X(P1) = X(P2) |
|||
320 X(P2) = H: RETURN</syntaxhighlight>Example:<syntaxhighlight lang="applesoftbasic">X(0)=4.4 : X(1)=2.3 : X(2)=-1.7 : X(3)=7.5 : X(4)=6.6 : X(5)=0.0 : X(6)=1.9 : X(7)=8.2 : X(8)=9.3 : X(9)=4.5 : X(10)=-11.7 |
|||
L = 11 : GOSUB 100MEDIAN |
|||
? R</syntaxhighlight>Output:<pre>5.95</pre> |
|||
=={{header|ARM Assembly}}== |
|||
{{works with|as|Raspberry Pi <br> or android 32 bits with application Termux}} |
|||
<syntaxhighlight lang ARM Assembly> |
|||
/* ARM assembly Raspberry PI */ |
|||
/* program averageMed.s */ |
|||
/* use quickselect look pseudo code in wikipedia quickselect */ |
|||
/************************************/ |
|||
/* Constantes */ |
|||
/************************************/ |
|||
/* for constantes see task include a file in arm assembly */ |
|||
.include "../constantes.inc" |
|||
/*********************************/ |
|||
/* Initialized data */ |
|||
/*********************************/ |
|||
.data |
|||
szMessResultValue: .asciz "Result : " |
|||
szCarriageReturn: .asciz "\n" |
|||
.align 4 |
|||
TableNumber: .float 4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2 |
|||
.equ NBELEMENTS, (. - TableNumber) / 4 |
|||
TableNumber2: .float 4.1, 7.2, 1.7, 9.3, 4.4, 3.2 |
|||
.equ NBELEMENTS2, (. - TableNumber2) / 4 |
|||
/*********************************/ |
|||
/* UnInitialized data */ |
|||
/*********************************/ |
|||
.bss |
|||
sZoneConv: .skip 24 |
|||
sZoneConv1: .skip 24 |
|||
/*********************************/ |
|||
/* code section */ |
|||
/*********************************/ |
|||
.text |
|||
.global main |
|||
main: @ entry of program |
|||
ldr r0,iAdrTableNumber @ address number table |
|||
mov r1,#0 @ index first item |
|||
mov r2,#NBELEMENTS -1 @ index last item |
|||
bl searchMedian |
|||
ldr r0,iAdrTableNumber2 @ address number table 2 |
|||
mov r1,#0 @ index first item |
|||
mov r2,#NBELEMENTS2 -1 @ index last item |
|||
bl searchMedian |
|||
100: @ standard end of the program |
|||
mov r0, #0 @ return code |
|||
mov r7, #EXIT @ request to exit program |
|||
svc #0 @ perform the system call |
|||
iAdrszCarriageReturn: .int szCarriageReturn |
|||
iAdrTableNumber: .int TableNumber |
|||
iAdrTableNumber2: .int TableNumber2 |
|||
iAdrsZoneConv: .int sZoneConv |
|||
iAdrszMessResultValue: .int szMessResultValue |
|||
/***************************************************/ |
|||
/* search median term in float array */ |
|||
/***************************************************/ |
|||
/* r0 contains the address of table */ |
|||
/* r1 contains index of first item */ |
|||
/* r2 contains index of last item */ |
|||
searchMedian: |
|||
push {r1-r5,lr} @ save registers |
|||
mov r5,r0 @ save array address |
|||
add r4,r1,r2 |
|||
add r4,r4,#1 @ sum numbers terms |
|||
tst r4,#1 @ odd ? |
|||
bne 1f |
|||
lsr r3,r4,#1 @ compute median index |
|||
bl select @ call selection |
|||
vmov s0,r0 @ save first result |
|||
sub r3,r3,#1 @ second term |
|||
mov r0,r5 |
|||
bl select @ call selection |
|||
vmov s1,r0 @ save 2ieme résult |
|||
vadd.f32 s0,s1 @ compute average two résults |
|||
mov r0,#2 |
|||
vmov s1,r0 |
|||
vcvt.f32.u32 s1,s1 @ conversion integer -> float |
|||
vdiv.f32 s0,s0,s1 |
|||
b 2f |
|||
1: @ even |
|||
lsr r3,r4,#1 |
|||
bl select @ call selection |
|||
vmov s0,r0 |
|||
2: |
|||
ldr r0,iAdrsZoneConv @ conversion float in decimal string |
|||
bl convertirFloat |
|||
mov r0,#3 @ and display result |
|||
ldr r1,iAdrszMessResultValue |
|||
ldr r2,iAdrsZoneConv |
|||
ldr r3,iAdrszCarriageReturn |
|||
bl displayStrings |
|||
100: @ end function |
|||
pop {r1-r5,pc} @ restaur register |
|||
/***************************************************/ |
|||
/* Appel récursif selection */ |
|||
/***************************************************/ |
|||
/* r0 contains the address of table */ |
|||
/* r1 contains index of first item */ |
|||
/* r2 contains index of last item */ |
|||
/* r3 contains search index */ |
|||
/* r0 return final value in float */ |
|||
/* remark : the final result is a float returned in r0 register */ |
|||
select: |
|||
push {r1-r6,lr} @ save registers |
|||
mov r6,r3 @ save search index |
|||
cmp r1,r2 @ first = last ? |
|||
ldreq r0,[r0,r1,lsl #2] @ return value of first index |
|||
beq 100f @ yes -> end |
|||
add r3,r1,r2 |
|||
lsr r3,r3,#1 @ compute median pivot |
|||
mov r4,r0 @ save r0 |
|||
mov r5,r2 @ save r2 |
|||
bl partition @ cutting into 2 parts |
|||
cmp r6,r0 @ pivot is ok ? |
|||
ldreq r0,[r4,r0,lsl #2] @ return value |
|||
beq 100f |
|||
bgt 1f |
|||
sub r2,r0,#1 @ index partition - 1 |
|||
mov r0,r4 @ array address |
|||
mov r3,r6 @ search index |
|||
bl select @ select lower part |
|||
b 100f |
|||
1: |
|||
add r1,r0,#1 @ index begin = index partition + 1 |
|||
mov r0,r4 @ array address |
|||
mov r2,r5 @ last item |
|||
mov r3,r6 @ search index |
|||
bl select @ select higter part |
|||
100: @ end function |
|||
pop {r1-r6,pc} @ restaur register |
|||
/******************************************************************/ |
|||
/* Partition table elements */ |
|||
/******************************************************************/ |
|||
/* r0 contains the address of table */ |
|||
/* r1 contains index of first item */ |
|||
/* r2 contains index of last item */ |
|||
/* r3 contains index of pivot */ |
|||
partition: |
|||
push {r1-r6,lr} @ save registers |
|||
ldr r4,[r0,r3,lsl #2] @ load value of pivot |
|||
ldr r5,[r0,r2,lsl #2] @ load value last index |
|||
str r5,[r0,r3,lsl #2] @ swap value of pivot |
|||
str r4,[r0,r2,lsl #2] @ and value last index |
|||
mov r3,r1 @ init with first index |
|||
1: @ begin loop |
|||
ldr r6,[r0,r3,lsl #2] @ load value |
|||
cmp r6,r4 @ compare loop value and pivot value |
|||
ldrlt r5,[r0,r1,lsl #2] @ if < swap value table |
|||
strlt r6,[r0,r1,lsl #2] |
|||
strlt r5,[r0,r3,lsl #2] |
|||
addlt r1,#1 @ and increment index 1 |
|||
add r3,#1 @ increment index 2 |
|||
cmp r3,r2 @ end ? |
|||
blt 1b @ no loop |
|||
ldr r5,[r0,r1,lsl #2] @ swap value |
|||
str r4,[r0,r1,lsl #2] |
|||
str r5,[r0,r2,lsl #2] |
|||
mov r0,r1 @ return index partition |
|||
100: |
|||
pop {r1-r6,pc} |
|||
/***************************************************/ |
|||
/* display multi strings */ |
|||
/***************************************************/ |
|||
/* r0 contains number strings address */ |
|||
/* r1 address string1 */ |
|||
/* r2 address string2 */ |
|||
/* r3 address string3 */ |
|||
/* other address on the stack */ |
|||
/* thinck to add number other address * 4 to add to the stack */ |
|||
displayStrings: @ INFO: displayStrings |
|||
push {r1-r4,fp,lr} @ save des registres |
|||
add fp,sp,#24 @ save paraméters address (6 registers saved * 4 bytes) |
|||
mov r4,r0 @ save strings number |
|||
cmp r4,#0 @ 0 string -> end |
|||
ble 100f |
|||
mov r0,r1 @ string 1 |
|||
bl affichageMess |
|||
cmp r4,#1 @ number > 1 |
|||
ble 100f |
|||
mov r0,r2 |
|||
bl affichageMess |
|||
cmp r4,#2 |
|||
ble 100f |
|||
mov r0,r3 |
|||
bl affichageMess |
|||
cmp r4,#3 |
|||
ble 100f |
|||
mov r3,#3 |
|||
sub r2,r4,#4 |
|||
1: @ loop extract address string on stack |
|||
ldr r0,[fp,r2,lsl #2] |
|||
bl affichageMess |
|||
subs r2,#1 |
|||
bge 1b |
|||
100: |
|||
pop {r1-r4,fp,pc} |
|||
/******************************************************************/ |
|||
/* Conversion Float */ |
|||
/******************************************************************/ |
|||
/* s0 contains Float */ |
|||
/* r0 contains address conversion area mini 20 charactèrs*/ |
|||
/* r0 return result length */ |
|||
/* see https://blog.benoitblanchon.fr/lightweight-float-to-string/ */ |
|||
convertirFloat: |
|||
push {r1-r7,lr} |
|||
vpush {s0-s2} |
|||
mov r6,r0 @ save area address |
|||
vmov r0,s0 |
|||
mov r1,#0 |
|||
vmov s1,r1 |
|||
movs r7,#0 @ result length |
|||
movs r3,#'+' |
|||
strb r3,[r6] @ sign + forcing |
|||
mov r2,r0 |
|||
lsls r2,#1 @ extraction bit 31 |
|||
bcc 1f @ positive ? |
|||
lsrs r0,r2,#1 @ raz sign if negative |
|||
movs r3,#'-' @ sign - |
|||
strb r3,[r6] |
|||
1: |
|||
adds r7,#1 @ next position |
|||
cmp r0,#0 @ case of positive or negative 0 |
|||
bne 2f |
|||
movs r3,#'0' |
|||
strb r3,[r6,r7] @ store character 0 |
|||
adds r7,#1 @ next position |
|||
movs r3,#0 |
|||
strb r3,[r6,r7] @ store 0 final |
|||
mov r0,r7 @ return length |
|||
b 100f @ and end |
|||
2: |
|||
ldr r2,iMaskExposant |
|||
mov r1,r0 |
|||
ands r1,r2 @ exposant = 255 ? |
|||
cmp r1,r2 |
|||
bne 4f |
|||
lsls r0,#10 @ bit 22 à 0 ? |
|||
bcc 3f @ yes |
|||
movs r2,#'N' @ case of Nan. store byte, if not possible store int |
|||
strb r2,[r6] @ area no aligned |
|||
movs r2,#'a' |
|||
strb r2,[r6,#1] |
|||
movs r2,#'n' |
|||
strb r2,[r6,#2] |
|||
movs r2,#0 @ 0 final |
|||
strb r2,[r6,#3] |
|||
movs r0,#3 @ return length 3 |
|||
b 100f |
|||
3: @ case infini positive or négative |
|||
movs r2,#'I' |
|||
strb r2,[r6,r7] |
|||
adds r7,#1 |
|||
movs r2,#'n' |
|||
strb r2,[r6,r7] |
|||
adds r7,#1 |
|||
movs r2,#'f' |
|||
strb r2,[r6,r7] |
|||
adds r7,#1 |
|||
movs r2,#0 |
|||
strb r2,[r6,r7] |
|||
mov r0,r7 |
|||
b 100f |
|||
4: |
|||
bl normaliserFloat |
|||
mov r5,r0 @ save exposant |
|||
VCVT.U32.f32 s2,s0 @ integer value of integer part |
|||
vmov r0,s2 @ integer part |
|||
VCVT.F32.U32 s1,s2 @ conversion float |
|||
vsub.f32 s1,s0,s1 @ extraction fract part |
|||
vldr s2,iConst1 |
|||
vmul.f32 s1,s2,s1 @ to crop it in full |
|||
VCVT.U32.f32 s1,s1 @ integer conversion |
|||
vmov r4,s1 @ fract value |
|||
@ integer conversion in r0 |
|||
mov r2,r6 @ save address area begin |
|||
adds r6,r7 |
|||
mov r1,r6 |
|||
bl conversion10 |
|||
add r6,r0 |
|||
movs r3,#',' |
|||
strb r3,[r6] |
|||
adds r6,#1 |
|||
mov r0,r4 @ conversion fractional part |
|||
mov r1,r6 |
|||
bl conversion10SP @ spécial routine with conservation begin 0 |
|||
add r6,r0 |
|||
subs r6,#1 |
|||
@ remove trailing zeros |
|||
5: |
|||
ldrb r0,[r6] |
|||
cmp r0,#'0' |
|||
bne 6f |
|||
subs r6,#1 |
|||
b 5b |
|||
6: |
|||
cmp r0,#',' |
|||
bne 7f |
|||
subs r6,#1 |
|||
7: |
|||
adds r6,#1 |
|||
movs r3,#'E' |
|||
strb r3,[r6] |
|||
adds r6,#1 |
|||
mov r0,r5 @ conversion exposant |
|||
mov r3,r0 |
|||
lsls r3,#1 |
|||
bcc 4f |
|||
rsbs r0,r0,#0 |
|||
movs r3,#'-' |
|||
strb r3,[r6] |
|||
adds r6,#1 |
|||
4: |
|||
mov r1,r6 |
|||
bl conversion10 |
|||
add r6,r0 |
|||
movs r3,#0 |
|||
strb r3,[r6] |
|||
adds r6,#1 |
|||
mov r0,r6 |
|||
subs r0,r2 @ return length result |
|||
subs r0,#1 @ - 0 final |
|||
100: |
|||
vpop {s0-s2} |
|||
pop {r1-r7,pc} |
|||
iMaskExposant: .int 0xFF<<23 |
|||
iConst1: .float 0f1E9 |
|||
/***************************************************/ |
|||
/* normaliser float */ |
|||
/***************************************************/ |
|||
/* r0 contain float value (always positive value and <> Nan) */ |
|||
/* s0 return new value */ |
|||
/* r0 return exposant */ |
|||
normaliserFloat: |
|||
push {lr} @ save registre |
|||
vmov s0,r0 @ value float |
|||
movs r0,#0 @ exposant |
|||
vldr s1,iConstE7 @ no normalisation for value < 1E7 |
|||
vcmp.f32 s0,s1 |
|||
vmrs APSR_nzcv,FPSCR |
|||
blo 10f @ if s0 < iConstE7 |
|||
vldr s1,iConstE32 |
|||
vcmp.f32 s0,s1 |
|||
vmrs APSR_nzcv,FPSCR |
|||
blo 1f |
|||
vldr s1,iConstE32 |
|||
vdiv.f32 s0,s0,s1 |
|||
adds r0,#32 |
|||
1: |
|||
vldr s1,iConstE16 |
|||
vcmp.f32 s0,s1 |
|||
vmrs APSR_nzcv,FPSCR |
|||
blo 2f |
|||
vldr s1,iConstE16 |
|||
vdiv.f32 s0,s0,s1 |
|||
adds r0,#16 |
|||
2: |
|||
vldr s1,iConstE8 |
|||
vcmp.f32 s0,s1 |
|||
vmrs APSR_nzcv,FPSCR |
|||
blo 3f |
|||
vldr s1,iConstE8 |
|||
vdiv.f32 s0,s0,s1 |
|||
adds r0,#8 |
|||
3: |
|||
vldr s1,iConstE4 |
|||
vcmp.f32 s0,s1 |
|||
vmrs APSR_nzcv,FPSCR |
|||
blo 4f |
|||
vldr s1,iConstE4 |
|||
vdiv.f32 s0,s0,s1 |
|||
adds r0,#4 |
|||
4: |
|||
vldr s1,iConstE2 |
|||
vcmp.f32 s0,s1 |
|||
vmrs APSR_nzcv,FPSCR |
|||
blo 5f |
|||
vldr s1,iConstE2 |
|||
vdiv.f32 s0,s0,s1 |
|||
adds r0,#2 |
|||
5: |
|||
vldr s1,iConstE1 |
|||
vcmp.f32 s0,s1 |
|||
vmrs APSR_nzcv,FPSCR |
|||
blo 10f |
|||
vldr s1,iConstE1 |
|||
vdiv.f32 s0,s0,s1 |
|||
adds r0,#1 |
|||
10: |
|||
vldr s1,iConstME5 @ pas de normalisation pour les valeurs > 1E-5 |
|||
vcmp.f32 s0,s1 |
|||
vmrs APSR_nzcv,FPSCR |
|||
bhi 100f |
|||
vldr s1,iConstME31 |
|||
vcmp.f32 s0,s1 |
|||
vmrs APSR_nzcv,FPSCR |
|||
bhi 11f |
|||
vldr s1,iConstE32 |
|||
vmul.f32 s0,s0,s1 |
|||
subs r0,#32 |
|||
11: |
|||
vldr s1,iConstME15 |
|||
vcmp.f32 s0,s1 |
|||
vmrs APSR_nzcv,FPSCR |
|||
bhi 12f |
|||
vldr s1,iConstE16 |
|||
vmul.f32 s0,s0,s1 |
|||
subs r0,#16 |
|||
12: |
|||
vldr s1,iConstME7 |
|||
vcmp.f32 s0,s1 |
|||
vmrs APSR_nzcv,FPSCR |
|||
bhi 13f |
|||
vldr s1,iConstE8 |
|||
vmul.f32 s0,s0,s1 |
|||
subs r0,#8 |
|||
13: |
|||
vldr s1,iConstME3 |
|||
vcmp.f32 s0,s1 |
|||
vmrs APSR_nzcv,FPSCR |
|||
bhi 14f |
|||
vldr s1,iConstE4 |
|||
vmul.f32 s0,s0,s1 |
|||
subs r0,#4 |
|||
14: |
|||
vldr s1,iConstME1 |
|||
vcmp.f32 s0,s1 |
|||
vmrs APSR_nzcv,FPSCR |
|||
bhi 15f |
|||
vldr s1,iConstE2 |
|||
vmul.f32 s0,s0,s1 |
|||
subs r0,#2 |
|||
15: |
|||
vldr s1,iConstE0 |
|||
vcmp.f32 s0,s1 |
|||
vmrs APSR_nzcv,FPSCR |
|||
bhi 100f |
|||
vldr s1,iConstE1 |
|||
vmul.f32 s0,s0,s1 |
|||
subs r0,#1 |
|||
100: @ fin standard de la fonction |
|||
pop {pc} @ restaur des registres |
|||
.align 2 |
|||
iConstE7: .float 0f1E7 |
|||
iConstE32: .float 0f1E32 |
|||
iConstE16: .float 0f1E16 |
|||
iConstE8: .float 0f1E8 |
|||
iConstE4: .float 0f1E4 |
|||
iConstE2: .float 0f1E2 |
|||
iConstE1: .float 0f1E1 |
|||
iConstME5: .float 0f1E-5 |
|||
iConstME31: .float 0f1E-31 |
|||
iConstME15: .float 0f1E-15 |
|||
iConstME7: .float 0f1E-7 |
|||
iConstME3: .float 0f1E-3 |
|||
iConstME1: .float 0f1E-1 |
|||
iConstE0: .float 0f1E0 |
|||
/******************************************************************/ |
|||
/* Décimal Conversion */ |
|||
/******************************************************************/ |
|||
/* r0 contain value et r1 address conversion area */ |
|||
conversion10SP: |
|||
push {r1-r6,lr} @ save registers |
|||
mov r5,r1 |
|||
mov r4,#8 |
|||
mov r2,r0 |
|||
mov r1,#10 @ conversion decimale |
|||
1: @ begin loop |
|||
mov r0,r2 @ copy number or quotients |
|||
bl division @ r0 dividende r1 divisor r2 quotient r3 remainder |
|||
add r3,#48 @ compute digit |
|||
strb r3,[r5,r4] @ store byte area address (r5) + offset (r4) |
|||
subs r4,r4,#1 @ position précedente |
|||
bge 1b @ and loop if not < zero |
|||
mov r0,#8 |
|||
mov r3,#0 |
|||
strb r3,[r5,r0] @ store 0 final |
|||
100: |
|||
pop {r1-r6,pc} @ restaur registers |
|||
/***************************************************/ |
|||
/* ROUTINES INCLUDE */ |
|||
/***************************************************/ |
|||
/* for this file see task include a file in language ARM assembly */ |
|||
.include "../affichage.inc" |
|||
</syntaxhighlight> |
|||
{{Out}} |
|||
<pre> |
|||
Result : +4,40000009E0 |
|||
Result : +4,25E0 |
|||
</pre> |
|||
=={{header|Arturo}}== |
|||
<syntaxhighlight lang="rebol">arr: [1 2 3 4 5 6 7] |
|||
arr2: [1 2 3 4 5 6] |
|||
print median arr |
|||
print median arr2</syntaxhighlight> |
|||
{{out}} |
|||
<pre>4 |
|||
3.5</pre> |
|||
See also: [[Mean]], [[Mode]] |
|||
=={{header|AutoHotkey}}== |
=={{header|AutoHotkey}}== |
||
Takes the lower of the middle two if length is even |
Takes the lower of the middle two if length is even |
||
<syntaxhighlight lang="autohotkey">seq = 4.1, 7.2, 1.7, 9.3, 4.4, 3.2, 5 |
|||
<lang AutoHotkey> |
|||
seq = 4.1, 7.2, 1.7, 9.3, 4.4, 3.2, 5 |
|||
MsgBox % median(seq, "`,") ; 4.1 |
MsgBox % median(seq, "`,") ; 4.1 |
||
Line 16: | Line 1,775: | ||
median := Floor(seq0 / 2) |
median := Floor(seq0 / 2) |
||
Return seq%median% |
Return seq%median% |
||
}</syntaxhighlight> |
|||
=={{header|AWK}}== |
|||
AWK arrays can be passed as parameters, but not returned, so they are usually global. |
|||
<syntaxhighlight lang="awk">#!/usr/bin/awk -f |
|||
BEGIN { |
|||
d[1] = 3.0 |
|||
d[2] = 4.0 |
|||
d[3] = 1.0 |
|||
d[4] = -8.4 |
|||
d[5] = 7.2 |
|||
d[6] = 4.0 |
|||
d[7] = 1.0 |
|||
d[8] = 1.2 |
|||
showD("Before: ") |
|||
gnomeSortD() |
|||
showD("Sorted: ") |
|||
printf "Median: %f\n", medianD() |
|||
exit |
|||
} |
} |
||
</lang> |
|||
function medianD( len, mid) { |
|||
len = length(d) |
|||
mid = int(len/2) + 1 |
|||
if (len % 2) return d[mid] |
|||
else return (d[mid] + d[mid-1]) / 2.0 |
|||
} |
|||
function gnomeSortD( i) { |
|||
for (i = 2; i <= length(d); i++) { |
|||
if (d[i] < d[i-1]) gnomeSortBackD(i) |
|||
} |
|||
} |
|||
function gnomeSortBackD(i, t) { |
|||
for (; i > 1 && d[i] < d[i-1]; i--) { |
|||
t = d[i] |
|||
d[i] = d[i-1] |
|||
d[i-1] = t |
|||
} |
|||
} |
|||
function showD(p, i) { |
|||
printf p |
|||
for (i = 1; i <= length(d); i++) { |
|||
printf d[i] " " |
|||
} |
|||
print "" |
|||
} |
|||
</syntaxhighlight> |
|||
Example output: |
|||
Before: 3 4 1 -8.4 7.2 4 1 1.2 |
|||
Sorted: -8.4 1 1 1.2 3 4 4 7.2 |
|||
Median: 2.100000 |
|||
=={{header|BaCon}}== |
|||
<syntaxhighlight lang="freebasic">DECLARE a[] = { 4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2 } TYPE FLOATING |
|||
DECLARE b[] = { 4.1, 7.2, 1.7, 9.3, 4.4, 3.2 } TYPE FLOATING |
|||
DEF FN Dim(x) = SIZEOF(x) / SIZEOF(double) |
|||
DEF FN Median(x) = IIF(ODD(Dim(x)), x[(Dim(x)-1)/2], (x[Dim(x)/2-1]+x[Dim(x)/2])/2 ) |
|||
SORT a |
|||
PRINT "Median of a: ", Median(a) |
|||
SORT b |
|||
PRINT "Median of b: ", Median(b)</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
Median of a: 4.4 |
|||
Median of b: 4.25 |
|||
</pre> |
|||
=={{header|BASIC}}== |
|||
{{works with|FreeBASIC}} |
|||
{{works with|PowerBASIC}} |
|||
{{works with|QB64}} |
|||
{{works with|QBasic}} |
|||
{{works with|Visual Basic}} |
|||
This uses the Quicksort function described at [[Quicksort#BASIC]], with <code>arr()</code>'s type changed to <code>SINGLE</code>. |
|||
Note that in order to truly work with the Windows versions of PowerBASIC, the module-level code must be contained inside <code>FUNCTION PBMAIN</code>. Similarly, in order to work under Visual Basic, the same module-level code must be contained with <code>Sub Main</code>. |
|||
<syntaxhighlight lang="qbasic">DECLARE FUNCTION median! (vector() AS SINGLE) |
|||
DIM vec1(10) AS SINGLE, vec2(11) AS SINGLE, n AS INTEGER |
|||
RANDOMIZE TIMER |
|||
FOR n = 0 TO 10 |
|||
vec1(n) = RND * 100 |
|||
vec2(n) = RND * 100 |
|||
NEXT |
|||
vec2(11) = RND * 100 |
|||
PRINT median(vec1()) |
|||
PRINT median(vec2()) |
|||
FUNCTION median! (vector() AS SINGLE) |
|||
DIM lb AS INTEGER, ub AS INTEGER, L0 AS INTEGER |
|||
lb = LBOUND(vector) |
|||
ub = UBOUND(vector) |
|||
REDIM v(lb TO ub) AS SINGLE |
|||
FOR L0 = lb TO ub |
|||
v(L0) = vector(L0) |
|||
NEXT |
|||
quicksort v(), lb, ub |
|||
IF ((ub - lb + 1) MOD 2) THEN |
|||
median = v((ub + lb) / 2) |
|||
ELSE |
|||
median = (v(INT((ub + lb) / 2)) + v(INT((ub + lb) / 2) + 1)) / 2 |
|||
END IF |
|||
END FUNCTION</syntaxhighlight> |
|||
See also: [[#BBC BASIC|BBC BASIC]], [[#Liberty BASIC|Liberty BASIC]], [[#PureBasic|PureBasic]], [[#TI-83 BASIC|TI-83 BASIC]], [[#TI-89 BASIC|TI-89 BASIC]]. |
|||
=={{header|BBC BASIC}}== |
|||
{{works with|BBC BASIC for Windows}} |
|||
<syntaxhighlight lang="bbcbasic"> INSTALL @lib$+"SORTLIB" |
|||
Sort% = FN_sortinit(0,0) |
|||
DIM a(6), b(5) |
|||
a() = 4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2 |
|||
b() = 4.1, 7.2, 1.7, 9.3, 4.4, 3.2 |
|||
PRINT "Median of a() is " ; FNmedian(a()) |
|||
PRINT "Median of b() is " ; FNmedian(b()) |
|||
END |
|||
DEF FNmedian(a()) |
|||
LOCAL C% |
|||
C% = DIM(a(),1) + 1 |
|||
CALL Sort%, a(0) |
|||
= (a(C% DIV 2) + a((C%-1) DIV 2)) / 2 |
|||
</syntaxhighlight> |
|||
Output: |
|||
<pre>Median of a() is 4.4 |
|||
Median of b() is 4.25</pre> |
|||
=={{header|BQN}}== |
|||
A tacit definition from [https://mlochbaum.github.io/bqncrate/ BQNcrate] which sorts and takes the middle elements of the array. |
|||
<pre>Median ← (+´÷≠)∧⊏˜2⌊∘÷˜¯1‿0+≠ |
|||
Median 5.961475‿2.025856‿7.262835‿1.814272‿2.281911‿4.854716</pre> |
|||
<pre>3.5683135</pre> |
|||
=={{header|Bracmat}}== |
|||
Each number is packaged in a little structure and these structures are accumulated in a sum. Bracmat keeps sums sorted, so the median is the term in the middle of the list, or the average of the two terms in the middle of the list. Notice that the input is converted to Bracmat's internal number representation, rational numbers, before being sorted. The output is converted back to 'double' variables. That last conversion is lossy. |
|||
<syntaxhighlight lang="bracmat">( ( median |
|||
= begin decimals end int list |
|||
, med med1 med2 num number |
|||
. ( convertToRational |
|||
= |
|||
. new$(UFP,'(.$arg:?V)) |
|||
: ?ufp |
|||
& (ufp..go)$ |
|||
& (ufp..export)$(Q.V) |
|||
) |
|||
& 0:?list |
|||
& whl |
|||
' ( !arg:%?number ?arg |
|||
& convertToRational$!number:?rationalnumber |
|||
& (!rationalnumber.)+!list:?list |
|||
) |
|||
& !list:?+[?end |
|||
& ( !end*1/2:~/ |
|||
& !list |
|||
: ? |
|||
+ [!(=1/2*!end+-1) |
|||
+ (?med1.?) |
|||
+ (?med2.?) |
|||
+ ? |
|||
& !med1*1/2+!med2*1/2:?med |
|||
| !list:?+[(div$(1/2*!end,1))+(?med.)+? |
|||
) |
|||
& (new$(UFP,'(.$med)).go)$ |
|||
) |
|||
& out$(median$("4.1" 4 "1.2" "6.235" "7868.33")) |
|||
& out |
|||
$ ( median |
|||
$ ( "4.4" |
|||
"2.3" |
|||
"-1.7" |
|||
"7.5" |
|||
"6.6" |
|||
"0.0" |
|||
"1.9" |
|||
"8.2" |
|||
"9.3" |
|||
"4.5" |
|||
) |
|||
) |
|||
& out$(median$(1 5 3 2 4)) |
|||
& out$(median$(1 5 3 6 4 2)) |
|||
);</syntaxhighlight> |
|||
Output: |
|||
<pre>4.0999999999999996E+00 |
|||
4.4500000000000002E+00 |
|||
3.0000000000000000E+00 |
|||
3.5000000000000000E+00</pre> |
|||
=={{header|C}}== |
=={{header|C}}== |
||
< |
<syntaxhighlight lang="c">#include <stdio.h> |
||
#include <stdlib.h> |
#include <stdlib.h> |
||
Line 29: | Line 1,996: | ||
int floatcmp( const void *a, const void *b) { |
int floatcmp( const void *a, const void *b) { |
||
if |
if (*(const float *)a < *(const float *)b) return -1; |
||
else |
else return *(const float *)a > *(const float *)b; |
||
else return 0; |
|||
} |
} |
||
Line 51: | Line 2,017: | ||
printf("flist2 median is %7.2f\n", median(&flist2)); /* 4.60 */ |
printf("flist2 median is %7.2f\n", median(&flist2)); /* 4.60 */ |
||
return 0; |
return 0; |
||
}</ |
}</syntaxhighlight> |
||
===Quickselect algorithm=== |
|||
Average O(n) time: |
|||
<syntaxhighlight lang="c">#include <stdio.h> |
|||
#include <stdlib.h> |
|||
#include <time.h> |
|||
#define MAX_ELEMENTS 1000000 |
|||
/* Return the k-th smallest item in array x of length len */ |
|||
double quick_select(int k, double *x, int len) |
|||
{ |
|||
inline void swap(int a, int b) |
|||
{ |
|||
double t = x[a]; |
|||
x[a] = x[b], x[b] = t; |
|||
} |
|||
int left = 0, right = len - 1; |
|||
int pos, i; |
|||
double pivot; |
|||
while (left < right) |
|||
{ |
|||
pivot = x[k]; |
|||
swap(k, right); |
|||
for (i = pos = left; i < right; i++) |
|||
{ |
|||
if (x[i] < pivot) |
|||
{ |
|||
swap(i, pos); |
|||
pos++; |
|||
} |
|||
} |
|||
swap(right, pos); |
|||
if (pos == k) break; |
|||
if (pos < k) left = pos + 1; |
|||
else right = pos - 1; |
|||
} |
|||
return x[k]; |
|||
} |
|||
int main(void) |
|||
{ |
|||
int i, length; |
|||
double *x, median; |
|||
/* Initialize random length double array with random doubles */ |
|||
srandom(time(0)); |
|||
length = random() % MAX_ELEMENTS; |
|||
x = malloc(sizeof(double) * length); |
|||
for (i = 0; i < length; i++) |
|||
{ |
|||
// shifted by RAND_MAX for negative values |
|||
// divide by a random number for floating point |
|||
x[i] = (double)(random() - RAND_MAX / 2) / (random() + 1); // + 1 to not divide by 0 |
|||
} |
|||
if (length % 2 == 0) // Even number of elements, median is average of middle two |
|||
{ |
|||
median = (quick_select(length / 2, x, length) + quick_select(length / 2 - 1, x, length / 2)) / 2; |
|||
} |
|||
else // select middle element |
|||
{ |
|||
median = quick_select(length / 2, x, length); |
|||
} |
|||
/* Sanity testing of median */ |
|||
int less = 0, more = 0, eq = 0; |
|||
for (i = 0; i < length; i++) |
|||
{ |
|||
if (x[i] < median) less ++; |
|||
else if (x[i] > median) more ++; |
|||
else eq ++; |
|||
} |
|||
printf("length: %d\nmedian: %lf\n<: %d\n>: %d\n=: %d\n", length, median, less, more, eq); |
|||
free(x); |
|||
return 0; |
|||
} |
|||
</syntaxhighlight> |
|||
Output: |
|||
<syntaxhighlight lang="c">length: 992021 |
|||
median: 0.000473 |
|||
<: 496010 |
|||
>: 496010 |
|||
=: 1</syntaxhighlight> |
|||
=={{header|C sharp|C#}}== |
|||
{{works with|C sharp|C#|10+}} |
|||
<syntaxhighlight lang="csharp"> |
|||
double median(double[] arr) |
|||
{ |
|||
var sorted = arr.OrderBy(x => x).ToList(); |
|||
var mid = arr.Length / 2; |
|||
return arr.Length % 2 == 0 |
|||
? (sorted[mid] + sorted[mid-1]) / 2 |
|||
: sorted[mid]; |
|||
} |
|||
var write = (double[] x) => |
|||
Console.WriteLine($"[{string.Join(", ", x)}]: {median(x)}"); |
|||
write(new double[] { 1, 5, 3, 6, 4, 2 }); //even |
|||
write(new double[] { 1, 5, 3, 6, 4, 2, 7 }); //odd |
|||
write(new double[] { 5 }); //single |
|||
</syntaxhighlight> |
|||
{{output}} |
|||
<pre> |
|||
[1, 5, 3, 6, 4, 2]: 3.5 |
|||
[1, 5, 3, 6, 4, 2, 7]: 4 |
|||
[5]: 5 |
|||
</pre> |
|||
=={{header|C++}}== |
=={{header|C++}}== |
||
This function runs in linear time on average. |
This function runs in linear time on average. |
||
< |
<syntaxhighlight lang="cpp">#include <algorithm> |
||
// inputs must be random-access iterators of doubles |
// inputs must be random-access iterators of doubles |
||
Line 86: | Line 2,166: | ||
return 0; |
return 0; |
||
}</ |
}</syntaxhighlight> |
||
===Order Statistic Tree=== |
|||
Uses a GNU C++ policy-based data structure to compute median in O(log n) time. |
|||
{{libheader|gnu_pbds}} |
|||
<syntaxhighlight lang="cpp">#include <bits/stdc++.h> |
|||
#include <ext/pb_ds/assoc_container.hpp> |
|||
#include <ext/pb_ds/tree_policy.hpp> |
|||
// the std::less_equal<> comparator allows the tree to support duplicates |
|||
typedef __gnu_pbds::tree<double, __gnu_pbds::null_type, std::less_equal<double>, __gnu_pbds::rb_tree_tag, __gnu_pbds::tree_order_statistics_node_update> ost_t; |
|||
// The lookup method, find_by_order (aka Select), is O(log n) for this data structure, much faster than std::nth_element() |
|||
double median(ost_t &OST) |
|||
{ |
|||
int n = OST.size(); |
|||
int m = n/2; |
|||
if (n == 1) |
|||
return *OST.find_by_order(0); |
|||
if (n == 2) |
|||
return (*OST.find_by_order(0) + *OST.find_by_order(1)) / 2; |
|||
if (n & 1) // odd number of elements |
|||
return *OST.find_by_order(m); |
|||
else // even number of elements |
|||
return (*OST.find_by_order(m) + *OST.find_by_order(m-1)) / 2; |
|||
} |
|||
int main(int argc, char* argv[]) |
|||
{ |
|||
ost_t ostree; |
|||
// insertion is also O(log n) for OSTs |
|||
ostree.insert(4.1); |
|||
ostree.insert(7.2); |
|||
ostree.insert(1.7); |
|||
ostree.insert(9.3); |
|||
ostree.insert(4.4); |
|||
ostree.insert(3.2); |
|||
printf("%.3f\n", median(ostree)); // 4.250 |
|||
return 0; |
|||
} |
|||
</syntaxhighlight> |
|||
=={{header|Clojure}}== |
|||
Simple: |
|||
<syntaxhighlight lang="lisp">(defn median [ns] |
|||
(let [ns (sort ns) |
|||
cnt (count ns) |
|||
mid (bit-shift-right cnt 1)] |
|||
(if (odd? cnt) |
|||
(nth ns mid) |
|||
(/ (+ (nth ns mid) (nth ns (dec mid))) 2))))</syntaxhighlight> |
|||
=={{header|COBOL}}== |
|||
Intrinsic function: |
|||
<syntaxhighlight lang="cobol">FUNCTION MEDIAN(some-table (ALL))</syntaxhighlight> |
|||
=={{header|Common Lisp}}== |
|||
The recursive partitioning solution, without the median of medians optimization. |
|||
<syntaxhighlight lang="lisp">((defun select-nth (n list predicate) |
|||
"Select nth element in list, ordered by predicate, modifying list." |
|||
(do ((pivot (pop list)) |
|||
(ln 0) (left '()) |
|||
(rn 0) (right '())) |
|||
((endp list) |
|||
(cond |
|||
((< n ln) (select-nth n left predicate)) |
|||
((eql n ln) pivot) |
|||
((< n (+ ln rn 1)) (select-nth (- n ln 1) right predicate)) |
|||
(t (error "n out of range.")))) |
|||
(if (funcall predicate (first list) pivot) |
|||
(psetf list (cdr list) |
|||
(cdr list) left |
|||
left list |
|||
ln (1+ ln)) |
|||
(psetf list (cdr list) |
|||
(cdr list) right |
|||
right list |
|||
rn (1+ rn))))) |
|||
(defun median (list predicate) |
|||
(select-nth (floor (length list) 2) list predicate))</syntaxhighlight> |
|||
=={{header|Craft Basic}}== |
|||
<syntaxhighlight lang="basic">define limit = 10, iterations = 6 |
|||
define iteration, size, middle, plusone |
|||
define point, top, high, low, pivot |
|||
dim list[limit] |
|||
dim stack[limit] |
|||
for iteration = 1 to iterations |
|||
gosub fill |
|||
gosub median |
|||
next iteration |
|||
end |
|||
sub fill |
|||
print "list: ", |
|||
erasearray list |
|||
let size = int(rnd * limit) + 1 |
|||
if size <= 2 then |
|||
let size = 3 |
|||
endif |
|||
for i = 0 to size - 1 |
|||
let list[i] = rnd * 1000 + rnd |
|||
print list[i], |
|||
gosub printcomma |
|||
next i |
|||
return |
|||
sub median |
|||
gosub sort |
|||
print newline, "size: ", size, tab, |
|||
let middle = int((size - 1)/ 2) |
|||
print "middle: ", middle + 1, tab, |
|||
if size mod 2 then |
|||
print "median: ", list[middle] |
|||
else |
|||
let plusone = middle + 1 |
|||
print "median: ", (list[middle] + list[plusone]) / 2 |
|||
endif |
|||
print |
|||
return |
|||
sub sort |
|||
let low = 0 |
|||
let high = size - 1 |
|||
let top = -1 |
|||
let top = top + 1 |
|||
let stack[top] = low |
|||
let top = top + 1 |
|||
let stack[top] = high |
|||
do |
|||
if top < 0 then |
|||
break |
|||
endif |
|||
let high = stack[top] |
|||
let top = top - 1 |
|||
let low = stack[top] |
|||
let top = top - 1 |
|||
let i = low - 1 |
|||
for j = low to high - 1 |
|||
if list[j] <= list[high] then |
|||
let i = i + 1 |
|||
let t = list[i] |
|||
let list[i] = list[j] |
|||
let list[j] = t |
|||
endif |
|||
next j |
|||
let point = i + 1 |
|||
let t = list[point] |
|||
let list[point] = list[high] |
|||
let list[high] = t |
|||
let pivot = i + 1 |
|||
if pivot - 1 > low then |
|||
let top = top + 1 |
|||
let stack[top] = low |
|||
let top = top + 1 |
|||
let stack[top] = pivot - 1 |
|||
endif |
|||
if pivot + 1 < high then |
|||
let top = top + 1 |
|||
let stack[top] = pivot + 1 |
|||
let top = top + 1 |
|||
let stack[top] = high |
|||
endif |
|||
wait |
|||
loop top >= 0 |
|||
print newline, "sorted: ", |
|||
for i = 0 to size - 1 |
|||
print list[i], |
|||
gosub printcomma |
|||
next i |
|||
return |
|||
sub printcomma |
|||
if i < size - 1 then |
|||
print comma, " ", |
|||
endif |
|||
return</syntaxhighlight> |
|||
{{out| Output}} |
|||
<pre> |
|||
list: 290.66, 870.46, 880.86 |
|||
sorted: 290.66, 870.46, 880.86 |
|||
size: 3 middle: 2 median: 870.46 |
|||
list: 910.91, 50.79, 790.58, 960.61 |
|||
sorted: 50.79, 790.58, 910.91, 960.61 |
|||
size: 4 middle: 2 median: 850.74 |
|||
list: 570.31, 500.16, 490.97, 370.48, 240.18, 880.23, 190.61, 950.19 |
|||
sorted: 190.61, 240.18, 370.48, 490.97, 500.16, 570.31, 880.23, 950.19 |
|||
size: 8 middle: 4 median: 495.57 |
|||
list: 120.87, 570.87, 570.85, 800.27, 200.04, 250.09, 870.04, 200.58, 800.61 |
|||
sorted: 120.87, 200.04, 200.58, 250.09, 570.85, 570.87, 800.27, 800.61, 870.04 |
|||
size: 9 middle: 5 median: 570.85 |
|||
list: 810.33, 760.55, 420.22, 730.64, 350.96 |
|||
sorted: 350.96, 420.22, 730.64, 760.55, 810.33 |
|||
size: 5 middle: 3 median: 730.64 |
|||
list: 40.12, 860.77, 960.29, 920.13 |
|||
sorted: 40.12, 860.77, 920.13, 960.29 |
|||
size: 4 middle: 2 median: 890.45 |
|||
</pre> |
|||
=={{header|Crystal}}== |
|||
<syntaxhighlight lang="ruby">def median(ary) |
|||
srtd = ary.sort |
|||
alen = srtd.size |
|||
0.5*(srtd[(alen-1)//2] + srtd[alen//2]) |
|||
end |
|||
a = [4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2] |
|||
puts median a |
|||
a = [4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2, 5.0] |
|||
puts median a |
|||
a = [5.0] |
|||
puts median a |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
4.4 |
|||
4.7 |
|||
5.0 |
|||
</pre> |
|||
=={{header|D}}== |
|||
<syntaxhighlight lang="d">import std.stdio, std.algorithm; |
|||
T median(T)(T[] nums) pure nothrow { |
|||
nums.sort(); |
|||
if (nums.length & 1) |
|||
return nums[$ / 2]; |
|||
else |
|||
return (nums[$ / 2 - 1] + nums[$ / 2]) / 2.0; |
|||
} |
|||
void main() { |
|||
auto a1 = [5.1, 2.6, 6.2, 8.8, 4.6, 4.1]; |
|||
writeln("Even median: ", a1.median); |
|||
auto a2 = [5.1, 2.6, 8.8, 4.6, 4.1]; |
|||
writeln("Odd median: ", a2.median); |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre>Even median: 4.85 |
|||
Odd median: 4.6</pre> |
|||
=={{header|Delphi}}== |
|||
<syntaxhighlight lang="delphi">program AveragesMedian; |
|||
{$APPTYPE CONSOLE} |
|||
uses Generics.Collections, Types; |
|||
function Median(aArray: TDoubleDynArray): Double; |
|||
var |
|||
lMiddleIndex: Integer; |
|||
begin |
|||
TArray.Sort<Double>(aArray); |
|||
lMiddleIndex := Length(aArray) div 2; |
|||
if Odd(Length(aArray)) then |
|||
Result := aArray[lMiddleIndex] |
|||
else |
|||
Result := (aArray[lMiddleIndex - 1] + aArray[lMiddleIndex]) / 2; |
|||
end; |
|||
begin |
|||
Writeln(Median(TDoubleDynArray.Create(4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2))); |
|||
Writeln(Median(TDoubleDynArray.Create(4.1, 7.2, 1.7, 9.3, 4.4, 3.2))); |
|||
end.</syntaxhighlight> |
|||
=={{header|E}}== |
|||
TODO: Use the selection algorithm, whatever that is |
|||
<syntaxhighlight lang="e">def median(list) { |
|||
def sorted := list.sort() |
|||
def count := sorted.size() |
|||
def mid1 := count // 2 |
|||
def mid2 := (count - 1) // 2 |
|||
if (mid1 == mid2) { # avoid inexact division |
|||
return sorted[mid1] |
|||
} else { |
|||
return (sorted[mid1] + sorted[mid2]) / 2 |
|||
} |
|||
}</syntaxhighlight> |
|||
<syntaxhighlight lang="e">? median([1,9,2]) |
|||
# value: 2 |
|||
? median([1,9,2,4]) |
|||
# value: 3.0</syntaxhighlight> |
|||
=={{header|EasyLang}}== |
|||
<syntaxhighlight lang="text"> |
|||
proc quickselect k . list[] res . |
|||
# |
|||
subr partition |
|||
mid = left |
|||
for i = left + 1 to right |
|||
if list[i] < list[left] |
|||
mid += 1 |
|||
swap list[i] list[mid] |
|||
. |
|||
. |
|||
swap list[left] list[mid] |
|||
. |
|||
left = 1 |
|||
right = len list[] |
|||
while left < right |
|||
partition |
|||
if mid < k |
|||
left = mid + 1 |
|||
elif mid > k |
|||
right = mid - 1 |
|||
else |
|||
left = right |
|||
. |
|||
. |
|||
res = list[k] |
|||
. |
|||
proc median . list[] res . |
|||
h = len list[] div 2 + 1 |
|||
quickselect h list[] res |
|||
if len list[] mod 2 = 0 |
|||
quickselect h - 1 list[] h |
|||
res = (res + h) / 2 |
|||
. |
|||
. |
|||
test[] = [ 4.1 5.6 7.2 1.7 9.3 4.4 3.2 ] |
|||
median test[] med |
|||
print med |
|||
test[] = [ 4.1 7.2 1.7 9.3 4.4 3.2 ] |
|||
median test[] med |
|||
print med |
|||
</syntaxhighlight> |
|||
<pre> |
|||
4.40 |
|||
4.25 |
|||
</pre> |
|||
=={{header|EchoLisp}}== |
|||
<syntaxhighlight lang="scheme"> |
|||
(define (median L) ;; O(n log(n)) |
|||
(set! L (vector-sort! < (list->vector L))) |
|||
(define dim (// (vector-length L) 2)) |
|||
(if (integer? dim) |
|||
(// (+ [L dim] [L (1- dim)]) 2) |
|||
[L (floor dim)])) |
|||
(median '( 3 4 5)) |
|||
→ 4 |
|||
(median '(6 5 4 3)) |
|||
→ 4.5 |
|||
(median (iota 10000)) |
|||
→ 4999.5 |
|||
(median (iota 10001)) |
|||
→ 5000 |
|||
</syntaxhighlight> |
|||
=={{header|Elena}}== |
|||
ELENA 6.x : |
|||
<syntaxhighlight lang="elena">import system'routines; |
|||
import system'math; |
|||
import extensions; |
|||
extension op |
|||
{ |
|||
get Median() |
|||
{ |
|||
var sorted := self.ascendant(); |
|||
var len := sorted.Length; |
|||
if (len == 0) |
|||
{ |
|||
^ nil |
|||
} |
|||
else |
|||
{ |
|||
var middleIndex := len / 2; |
|||
if (len.mod(2) == 0) |
|||
{ |
|||
^ (sorted[middleIndex - 1] + sorted[middleIndex]) / 2 |
|||
} |
|||
else |
|||
{ |
|||
^ sorted[middleIndex] |
|||
} |
|||
} |
|||
} |
|||
} |
|||
public program() |
|||
{ |
|||
var a1 := new real[]{4.1r, 5.6r, 7.2r, 1.7r, 9.3r, 4.4r, 3.2r}; |
|||
var a2 := new real[]{4.1r, 7.2r, 1.7r, 9.3r, 4.4r, 3.2r}; |
|||
console.printLine("median of (",a1.asEnumerable(),") is ",a1.Median); |
|||
console.printLine("median of (",a2.asEnumerable(),") is ",a2.Median); |
|||
console.readChar() |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
median of (4.1,5.6,7.2,1.7,9.3,4.4,3.2) is 4.4 |
|||
median of (4.1,7.2,1.7,9.3,4.4,3.2) is 4.25 |
|||
</pre> |
|||
=={{header|Elixir}}== |
|||
{{trans|Erlang}} |
|||
<syntaxhighlight lang="elixir">defmodule Average do |
|||
def median([]), do: nil |
|||
def median(list) do |
|||
len = length(list) |
|||
sorted = Enum.sort(list) |
|||
mid = div(len, 2) |
|||
if rem(len,2) == 0, do: (Enum.at(sorted, mid-1) + Enum.at(sorted, mid)) / 2, |
|||
else: Enum.at(sorted, mid) |
|||
end |
|||
end |
|||
median = fn list -> IO.puts "#{inspect list} => #{inspect Average.median(list)}" end |
|||
median.([]) |
|||
Enum.each(1..6, fn i -> |
|||
(for _ <- 1..i, do: :rand.uniform(6)) |> median.() |
|||
end)</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
[] => nil |
|||
[4] => 4 |
|||
[1, 6] => 3.5 |
|||
[5, 2, 4] => 4 |
|||
[2, 3, 5, 1] => 2.5 |
|||
[3, 2, 6, 3, 2] => 3 |
|||
[6, 4, 2, 3, 1, 3] => 3.0 |
|||
</pre> |
|||
=={{header|EMal}}== |
|||
===Sort=== |
|||
<syntaxhighlight lang="emal"> |
|||
fun median = real by some real values |
|||
values = values.sort() |
|||
int mid = values.length / 2 |
|||
return when(values.length % 2 == 0, (values[mid] + values[mid - 1]) / 2.0, values[mid]) |
|||
end |
|||
writeLine(median(4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2, 5.0)) |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
4.7 |
|||
</pre> |
|||
===Quickselect=== |
|||
<syntaxhighlight lang="emal"> |
|||
fun median = real by some real values |
|||
fun swap = void by int a, int b |
|||
real t = values[a] |
|||
values[a] = values[b] |
|||
values[b] = t |
|||
end |
|||
fun select = real by int k |
|||
int left = 0 |
|||
int right = values.length - 1 |
|||
while left < right |
|||
real pivot = values[k] |
|||
swap(k, right) |
|||
int pos = left |
|||
for int i = left; i < right; i++ |
|||
if values[i] < pivot |
|||
swap(i, pos) |
|||
++pos |
|||
end |
|||
end |
|||
swap(right, pos) |
|||
if pos == k do break |
|||
else if pos < k do left = pos + 1 |
|||
else do right = pos - 1 end |
|||
end |
|||
return values[k] |
|||
end |
|||
int halfLength = values.length / 2 |
|||
return when(values.length % 2 == 0, |
|||
(select(halfLength) + select(halfLength - 1)) / 2.0, |
|||
select(halfLength)) |
|||
end |
|||
writeLine(median(4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2, 5.0)) |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
4.7 |
|||
</pre> |
|||
=={{header|Erlang}}== |
|||
<syntaxhighlight lang="erlang">-module(median). |
|||
-import(lists, [nth/2, sort/1]). |
|||
-compile(export_all). |
|||
test(MaxInt,ListSize,TimesToRun) -> |
|||
test(MaxInt,ListSize,TimesToRun,[[],[]]). |
|||
test(_,_,0,[GMAcc, OMAcc]) -> |
|||
Len = length(GMAcc), |
|||
{GMT,GMV} = lists:foldl(fun({T, V}, {AT,AV}) -> {AT + T, AV + V} end, {0,0}, GMAcc), |
|||
{OMT,OMV} = lists:foldl(fun({T, V}, {AT,AV}) -> {AT + T, AV + V} end, {0,0}, OMAcc), |
|||
io:format("QuickSelect Time: ~p, Val: ~p~nOriginal Time: ~p, Val: ~p~n", [GMT/Len, GMV/Len, OMT/Len, OMV/Len]); |
|||
test(M,N,T,[GMAcc, OMAcc]) -> |
|||
L = [rand:uniform(M) || _ <- lists:seq(1,N)], |
|||
GM = timer:tc(fun() -> qs_median(L) end), |
|||
OM = timer:tc(fun() -> median(L) end), |
|||
test(M,N,T-1,[[GM|GMAcc], [OM|OMAcc]]). |
|||
median(Unsorted) -> |
|||
Sorted = sort(Unsorted), |
|||
Length = length(Sorted), |
|||
Mid = Length div 2, |
|||
Rem = Length rem 2, |
|||
(nth(Mid+Rem, Sorted) + nth(Mid+1, Sorted)) / 2. |
|||
% *********************************************************** |
|||
% median based on quick select with optimizations for repeating numbers |
|||
% if it really matters it's a little faster |
|||
% by Roman Rabinovich |
|||
% *********************************************************** |
|||
qs_median([]) -> error; |
|||
qs_median([X]) -> X; |
|||
qs_median([P|_Tail] = List) -> |
|||
TargetPos = length(List)/2 + 0.5, |
|||
qs_median(List, TargetPos, P, 0). |
|||
qs_median([X], 1, _, 0) -> X; |
|||
qs_median([X], 1, _, Acc) -> (X + Acc)/2; |
|||
qs_median([P|Tail], TargetPos, LastP, Acc) -> |
|||
Smaller = [X || X <- Tail, X < P], |
|||
LS = length(Smaller), |
|||
qs_continue(P, LS, TargetPos, LastP, Smaller, Tail, Acc). |
|||
qs_continue(P, LS, TargetPos, _, _, _, 0) when LS + 1 == TargetPos -> P; |
|||
qs_continue(P, LS, TargetPos, _, _, _, Acc) when LS + 1 == TargetPos -> (P + Acc)/2; |
|||
qs_continue(P, 0, TargetPos, LastP, _SM, _TL, _Acc) when TargetPos == 0.5 -> |
|||
(P+LastP)/2; |
|||
qs_continue(P, LS, TargetPos, _LastP, SM, _TL, _Acc) when TargetPos == LS + 0.5 -> |
|||
qs_median(SM, TargetPos - 0.5, P, P); |
|||
qs_continue(P, LS, TargetPos, _LastP, SM, _TL, Acc) when LS + 1 > TargetPos -> |
|||
qs_median(SM, TargetPos, P, Acc); |
|||
qs_continue(P, LS, TargetPos, _LastP, _SM, TL, Acc) -> |
|||
Larger = [X || X <- TL, X >= P], |
|||
NewPos= TargetPos - LS -1, |
|||
case NewPos == 0.5 of |
|||
true -> |
|||
qs_median(Larger, 1, P, P); |
|||
false -> |
|||
qs_median(Larger, NewPos, P, Acc) |
|||
end. |
|||
</syntaxhighlight> |
|||
=={{header|ERRE}}== |
|||
<syntaxhighlight lang="text"> |
|||
PROGRAM MEDIAN |
|||
DIM X[10] |
|||
PROCEDURE QUICK_SELECT |
|||
LT=0 RT=L-1 |
|||
J=LT |
|||
REPEAT |
|||
PT=X[K] |
|||
SWAP(X[K],X[RT]) |
|||
P=LT |
|||
FOR I=P TO RT-1 DO |
|||
IF X[I]<PT THEN SWAP(X[I],X[P]) P=P+1 END IF |
|||
END FOR |
|||
SWAP(X[RT],X[P]) |
|||
IF P=K THEN EXIT PROCEDURE END IF |
|||
IF P<K THEN LT=P+1 END IF |
|||
IF P>=K THEN RT=P-1 END IF |
|||
UNTIL J>RT |
|||
END PROCEDURE |
|||
PROCEDURE MEDIAN |
|||
K=INT(L/2) |
|||
QUICK_SELECT |
|||
R=X[K] |
|||
IF L-2*INT(L/2)<>0 THEN R=(R+X[K+1])/2 END IF |
|||
END PROCEDURE |
|||
BEGIN |
|||
PRINT(CHR$(12);) !CLS |
|||
X[0]=4.4 X[1]=2.3 X[2]=-1.7 X[3]=7.5 X[4]=6.6 X[5]=0 |
|||
X[6]=1.9 X[7]=8.2 X[8]=9.3 X[9]=4.5 X[10]=-11.7 |
|||
L=11 |
|||
MEDIAN |
|||
PRINT(R) |
|||
END PROGRAM |
|||
</syntaxhighlight> |
|||
Ouput is 5.95 |
|||
=={{header|Euler Math Toolbox}}== |
|||
The following function does much more than computing the median. It can handle |
|||
a matrix of x values row by row. Then it can handle multiplicities in the vector |
|||
v. Moreover it can search for the p median, not only the p=0.5 median. |
|||
<syntaxhighlight lang="euler math toolbox"> |
|||
>type median |
|||
function median (x, v: none, p) |
|||
## Default for v : none |
|||
## Default for p : 0.5 |
|||
m=rows(x); |
|||
if m>1 then |
|||
y=zeros(m,1); |
|||
loop 1 to m; |
|||
y[#]=median(x[#],v,p); |
|||
end; |
|||
return y; |
|||
else |
|||
if v<>none then |
|||
{xs,i}=sort(x); vsh=v[i]; |
|||
n=cols(xs); |
|||
ns=sum(vsh); |
|||
i=1+p*(ns-1); i0=floor(i); |
|||
vs=cumsum(vsh); |
|||
loop 1 to n |
|||
if vs[#]>i0 then |
|||
return xs[#]; |
|||
elseif vs[#]+1>i0 then |
|||
k=#+1; |
|||
repeat; |
|||
if vsh[k]>0 or k>n then break; endif; |
|||
k=k+1; |
|||
end; |
|||
return (1-(i-i0))*xs[#]+(i-i0)*xs[k]+0; |
|||
endif; |
|||
end; |
|||
return xs[n]; |
|||
else |
|||
xs=sort(x); |
|||
n=cols(x); |
|||
i=1+p*(n-1); i0=floor(i); |
|||
if i0==n then return xs[n]; endif; |
|||
return (i-i0)*xs[i+1]+(1-(i-i0))*xs[i]; |
|||
endif; |
|||
endif; |
|||
endfunction |
|||
>median(1:10) |
|||
5.5 |
|||
>median(1:9) |
|||
5 |
|||
>median(1:10,p=0.2) |
|||
2.8 |
|||
>0.2*10+0.8*1 |
|||
2.8 |
|||
</syntaxhighlight> |
|||
=={{header|Euphoria}}== |
|||
<syntaxhighlight lang="euphoria">function median(sequence s) |
|||
atom min,k |
|||
-- Selection sort of half+1 |
|||
for i = 1 to length(s)/2+1 do |
|||
min = s[i] |
|||
k = 0 |
|||
for j = i+1 to length(s) do |
|||
if s[j] < min then |
|||
min = s[j] |
|||
k = j |
|||
end if |
|||
end for |
|||
if k then |
|||
s[k] = s[i] |
|||
s[i] = min |
|||
end if |
|||
end for |
|||
if remainder(length(s),2) = 0 then |
|||
return (s[$/2]+s[$/2+1])/2 |
|||
else |
|||
return s[$/2+1] |
|||
end if |
|||
end function |
|||
? median({ 4.4, 2.3, -1.7, 7.5, 6.6, 0.0, 1.9, 8.2, 9.3, 4.5 })</syntaxhighlight> |
|||
Output: |
|||
<pre>4.45 |
|||
</pre> |
|||
=={{header|Excel}}== |
|||
Assuming the values are entered in the A column, type into any cell which will not be part of the list : |
|||
<syntaxhighlight lang="excel"> |
|||
=MEDIAN(A1:A10) |
|||
</syntaxhighlight> |
|||
Assuming 10 values will be entered, alternatively, you can just type |
|||
<syntaxhighlight lang="excel"> |
|||
=MEDIAN( |
|||
</syntaxhighlight> |
|||
and then select the start and end cells, not necessarily in the same row or column. |
|||
The output for the first expression, for any 10 numbers is |
|||
<syntaxhighlight lang="text"> |
|||
23 11,5 |
|||
21 |
|||
12 |
|||
3 |
|||
19 |
|||
7 |
|||
23 |
|||
11 |
|||
9 |
|||
0 |
|||
</syntaxhighlight> |
|||
=={{header|F Sharp|F#}}== |
|||
Median of Medians algorithm implementation |
|||
<syntaxhighlight lang="fsharp"> |
|||
let rec splitToFives list = |
|||
match list with |
|||
| a::b::c::d::e::tail -> |
|||
([a;b;c;d;e])::(splitToFives tail) |
|||
| [] -> [] |
|||
| _ -> |
|||
let left = 5 - List.length (list) |
|||
let last = List.append list (List.init left (fun _ -> System.Double.PositiveInfinity) ) |
|||
in [last] |
|||
let medianFromFives = |
|||
List.map ( fun (i:float list) -> |
|||
List.nth (List.sort i) 2 ) |
|||
let start l = |
|||
let rec magicFives list k = |
|||
if List.length(list) <= 10 then |
|||
List.nth (List.sort list) (k-1) |
|||
else |
|||
let s = splitToFives list |
|||
let M = medianFromFives s |
|||
let m = magicFives M (int(System.Math.Ceiling((float(List.length M))/2.))) |
|||
let (ll,lg) = List.partition ( fun i -> i < m ) list |
|||
let (le,lg) = List.partition ( fun i -> i = m ) lg |
|||
in |
|||
if (List.length ll >= k) then |
|||
magicFives ll k |
|||
else if (List.length ll + List.length le >= k ) then m |
|||
else |
|||
magicFives lg (k-(List.length ll)-(List.length le)) |
|||
in |
|||
let len = List.length l in |
|||
if (len % 2 = 1) then |
|||
magicFives l ((len+1)/2) |
|||
else |
|||
let a = magicFives l (len/2) |
|||
let b = magicFives l ((len/2)+1) |
|||
in (a+b)/2. |
|||
let z = [1.;5.;2.;8.;7.;2.] |
|||
start z |
|||
let z' = [1.;5.;2.;8.;7.] |
|||
start z' |
|||
</syntaxhighlight> |
|||
=={{header|Factor}}== |
|||
The quicksort-style solution, with random pivoting. Takes the lesser of the two medians for even sequences. |
|||
<syntaxhighlight lang="factor">USING: arrays kernel locals math math.functions random sequences ; |
|||
IN: median |
|||
: pivot ( seq -- pivot ) random ; |
|||
: split ( seq pivot -- {lt,eq,gt} ) |
|||
[ [ < ] curry partition ] keep |
|||
[ = ] curry partition |
|||
3array ; |
|||
DEFER: nth-in-order |
|||
:: nth-in-order-recur ( seq ind -- elt ) |
|||
seq dup pivot split |
|||
dup [ length ] map 0 [ + ] accumulate nip |
|||
dup [ ind <= [ 1 ] [ 0 ] if ] map sum 1 - |
|||
[ swap nth ] curry bi@ |
|||
ind swap - |
|||
nth-in-order ; |
|||
: nth-in-order ( seq ind -- elt ) |
|||
dup 0 = |
|||
[ drop first ] |
|||
[ nth-in-order-recur ] |
|||
if ; |
|||
: median ( seq -- median ) |
|||
dup length 1 - 2 / floor nth-in-order ;</syntaxhighlight> |
|||
Usage: |
|||
<syntaxhighlight lang="factor">( scratchpad ) 11 iota median . |
|||
5 |
|||
( scratchpad ) 10 iota median . |
|||
4</syntaxhighlight> |
|||
=={{header|Forth}}== |
|||
This uses the O(n) algorithm derived from [[quicksort]]. |
|||
<syntaxhighlight lang="forth">-1 cells constant -cell |
|||
: cell- -cell + ; |
|||
defer lessthan ( a@ b@ -- ? ) ' < is lessthan |
|||
: mid ( l r -- mid ) over - 2/ -cell and + ; |
|||
: exch ( addr1 addr2 -- ) dup @ >r over @ swap ! r> swap ! ; |
|||
: part ( l r -- l r r2 l2 ) |
|||
2dup mid @ >r ( r: pivot ) |
|||
2dup begin |
|||
swap begin dup @ r@ lessthan while cell+ repeat |
|||
swap begin r@ over @ lessthan while cell- repeat |
|||
2dup <= if 2dup exch >r cell+ r> cell- then |
|||
2dup > until r> drop ; |
|||
0 value midpoint |
|||
: select ( l r -- ) |
|||
begin 2dup < while |
|||
part |
|||
dup midpoint >= if nip nip ( l l2 ) else |
|||
over midpoint <= if drop rot drop swap ( r2 r ) else |
|||
2drop 2drop exit then then |
|||
repeat 2drop ; |
|||
: median ( array len -- m ) |
|||
1- cells over + 2dup mid to midpoint |
|||
select midpoint @ ;</syntaxhighlight> |
|||
<syntaxhighlight lang="forth">create test 4 , 2 , 1 , 3 , 5 , |
|||
test 4 median . \ 2 |
|||
test 5 median . \ 3</syntaxhighlight> |
|||
=={{header|Fortran}}== |
=={{header|Fortran}}== |
||
{{works with|Fortran|90 and later}} |
{{works with|Fortran|90 and later}} |
||
< |
<syntaxhighlight lang="fortran">program Median_Test |
||
real :: a(7) = (/ 4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2 /), & |
real :: a(7) = (/ 4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2 /), & |
||
Line 133: | Line 3,120: | ||
end function median |
end function median |
||
end program Median_Test</ |
end program Median_Test</syntaxhighlight> |
||
If one refers to [[Quickselect_algorithm#Fortran]] which offers function FINDELEMENT(K,A,N) that returns the value of A(K) when the array of N elements has been rearranged if necessary so that A(K) is the K'th in order, then, supposing that a version is devised using the appropriate type for array A, <syntaxhighlight lang="fortran"> K = N/2 |
|||
MEDIAN = FINDELEMENT(K + 1,A,N) |
|||
IF (MOD(N,2).EQ.0) MEDIAN = (FINDELEMENT(K,A,N) + MEDIAN)/2 </syntaxhighlight> |
|||
As well as returning a result, the function possibly re-arranges the elements of the array, which is not "pure" behaviour. Not to the degree of fully sorting them, merely that all elements before K are not larger than A(K) as it now is, and all elements after K are not smaller than A(K). |
|||
=={{header|FreeBASIC}}== |
|||
<syntaxhighlight lang="freebasic">' FB 1.05.0 Win64 |
|||
Sub quicksort(a() As Double, first As Integer, last As Integer) |
|||
Dim As Integer length = last - first + 1 |
|||
If length < 2 Then Return |
|||
Dim pivot As Double = a(first + length\ 2) |
|||
Dim lft As Integer = first |
|||
Dim rgt As Integer = last |
|||
While lft <= rgt |
|||
While a(lft) < pivot |
|||
lft +=1 |
|||
Wend |
|||
While a(rgt) > pivot |
|||
rgt -= 1 |
|||
Wend |
|||
If lft <= rgt Then |
|||
Swap a(lft), a(rgt) |
|||
lft += 1 |
|||
rgt -= 1 |
|||
End If |
|||
Wend |
|||
quicksort(a(), first, rgt) |
|||
quicksort(a(), lft, last) |
|||
End Sub |
|||
Function median(a() As Double) As Double |
|||
Dim lb As Integer = LBound(a) |
|||
Dim ub As Integer = UBound(a) |
|||
Dim length As Integer = ub - lb + 1 |
|||
If length = 0 Then Return 0.0/0.0 '' NaN |
|||
If length = 1 Then Return a(ub) |
|||
Dim mb As Integer = (lb + ub) \2 |
|||
If length Mod 2 = 1 Then Return a(mb) |
|||
Return (a(mb) + a(mb + 1))/2.0 |
|||
End Function |
|||
Dim a(0 To 9) As Double = {4.4, 2.3, -1.7, 7.5, 6.6, 0.0, 1.9, 8.2, 9.3, 4.5} |
|||
quicksort(a(), 0, 9) |
|||
Print "Median for all 10 elements : "; median(a()) |
|||
' now get rid of final element |
|||
Dim b(0 To 8) As Double = {4.4, 2.3, -1.7, 7.5, 6.6, 0.0, 1.9, 8.2, 9.3} |
|||
quicksort(b(), 0, 8) |
|||
Print "Median for first 9 elements : "; median(b()) |
|||
Print |
|||
Print "Press any key to quit" |
|||
Sleep</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
Median for all 10 elements : 4.45 |
|||
Median for first 9 elements : 4.4 |
|||
</pre> |
|||
=={{header|FutureBasic}}== |
|||
FB has native averaging functions. |
|||
<syntaxhighlight lang="futurebasic"> |
|||
local fn MedianAverage( arguments as CFArrayRef ) as CFStringRef |
|||
ExpressionRef expRef = fn ExpressionForFunction( @"median:", @[fn ExpressionForConstantValue( arguments )] ) |
|||
CFNumberRef result = fn ExpressionValueWithObject( expRef, NULL, NULL ) |
|||
CFStringRef median = fn NumberStringValue( result ) |
|||
end fn = median |
|||
print fn MedianAverage( @[@1, @9, @2] ) // 2 |
|||
print fn MedianAverage( @[@1, @9, @2, @4] ) // 3 |
|||
print fn MedianAverage( @[@5.961475, @2.025856, @7.262835, @1.814272, @2.281911, @4.854716] ) // 3.5683135 |
|||
print fn MedianAverage( @[@4.1, @5.6, @7.2, @1.7, @9.3, @4.4, @3.2] ) // 4.4 |
|||
print fn MedianAverage( @[@40.12, @860.77, @960.29, @920.13] ) // 890.45 |
|||
HandleEvents |
|||
</syntaxhighlight> |
|||
{{output}} |
|||
<pre> |
|||
2 |
|||
3 |
|||
3.5683135 |
|||
4.4 |
|||
890.45 |
|||
</pre> |
|||
=={{header|GAP}}== |
|||
<syntaxhighlight lang="gap">Median := function(v) |
|||
local n, w; |
|||
w := SortedList(v); |
|||
n := Length(v); |
|||
return (w[QuoInt(n + 1, 2)] + w[QuoInt(n, 2) + 1]) / 2; |
|||
end; |
|||
a := [41, 56, 72, 17, 93, 44, 32]; |
|||
b := [41, 72, 17, 93, 44, 32]; |
|||
Median(a); |
|||
# 44 |
|||
Median(b); |
|||
# 85/2</syntaxhighlight> |
|||
=={{header|Go}}== |
|||
===Sort=== |
|||
Go built-in sort. O(n log n). |
|||
<syntaxhighlight lang="go">package main |
|||
import ( |
|||
"fmt" |
|||
"sort" |
|||
) |
|||
func main() { |
|||
fmt.Println(median([]float64{3, 1, 4, 1})) // prints 2 |
|||
fmt.Println(median([]float64{3, 1, 4, 1, 5})) // prints 3 |
|||
} |
|||
func median(a []float64) float64 { |
|||
sort.Float64s(a) |
|||
half := len(a) / 2 |
|||
m := a[half] |
|||
if len(a)%2 == 0 { |
|||
m = (m + a[half-1]) / 2 |
|||
} |
|||
return m |
|||
}</syntaxhighlight> |
|||
===Partial selection sort=== |
|||
The task description references the WP entry for "selection algorithm" which (as of this writing) gives just one pseudocode example, which is implemented here. As the WP article notes, it is O(kn). |
|||
Unfortunately in the case of median, k is n/2 so the algorithm is O(n^2). Still, it gives the idea of median by selection. Note that the partial selection sort does leave the k smallest values sorted, so in the case of an even number of elements, the two elements to average are available after a single call to sel(). |
|||
<syntaxhighlight lang="go">package main |
|||
import "fmt" |
|||
func main() { |
|||
fmt.Println(median([]float64{3, 1, 4, 1})) // prints 2 |
|||
fmt.Println(median([]float64{3, 1, 4, 1, 5})) // prints 3 |
|||
} |
|||
func median(a []float64) float64 { |
|||
half := len(a) / 2 |
|||
med := sel(a, half) |
|||
if len(a)%2 == 0 { |
|||
return (med + a[half-1]) / 2 |
|||
} |
|||
return med |
|||
} |
|||
func sel(list []float64, k int) float64 { |
|||
for i, minValue := range list[:k+1] { |
|||
minIndex := i |
|||
for j := i + 1; j < len(list); j++ { |
|||
if list[j] < minValue { |
|||
minIndex = j |
|||
minValue = list[j] |
|||
list[i], list[minIndex] = minValue, list[i] |
|||
} |
|||
} |
|||
} |
|||
return list[k] |
|||
}</syntaxhighlight> |
|||
===Quickselect=== |
|||
It doesn't take too much more code to implement a quickselect with random pivoting, which should run in expected time O(n). The qsel function here permutes elements of its parameter "a" in place. It leaves the slice somewhat more ordered, but unlike the sort and partial sort examples above, does not guarantee that element k-1 is in place. For the case of an even number of elements then, median must make two separate qsel() calls. |
|||
<syntaxhighlight lang="go">package main |
|||
import ( |
|||
"fmt" |
|||
"math/rand" |
|||
) |
|||
func main() { |
|||
fmt.Println(median([]float64{3, 1, 4, 1})) // prints 2 |
|||
fmt.Println(median([]float64{3, 1, 4, 1, 5})) // prints 3 |
|||
} |
|||
func median(list []float64) float64 { |
|||
half := len(list) / 2 |
|||
med := qsel(list, half) |
|||
if len(list)%2 == 0 { |
|||
return (med + qsel(list, half-1)) / 2 |
|||
} |
|||
return med |
|||
} |
|||
func qsel(a []float64, k int) float64 { |
|||
for len(a) > 1 { |
|||
px := rand.Intn(len(a)) |
|||
pv := a[px] |
|||
last := len(a) - 1 |
|||
a[px], a[last] = a[last], pv |
|||
px = 0 |
|||
for i, v := range a[:last] { |
|||
if v < pv { |
|||
a[px], a[i] = v, a[px] |
|||
px++ |
|||
} |
|||
} |
|||
if px == k { |
|||
return pv |
|||
} |
|||
if k < px { |
|||
a = a[:px] |
|||
} else { |
|||
// swap elements. simply assigning a[last] would be enough to |
|||
// allow qsel to return the correct result but it would leave slice |
|||
// "a" unusable for subsequent use. we want this full swap so that |
|||
// we can make two successive qsel calls in the case of median |
|||
// of an even number of elements. |
|||
a[px], a[last] = pv, a[px] |
|||
a = a[px+1:] |
|||
k -= px + 1 |
|||
} |
|||
} |
|||
return a[0] |
|||
}</syntaxhighlight> |
|||
=={{header|Groovy}}== |
|||
Solution (brute force sorting, with arithmetic averaging of dual midpoints (even sizes)): |
|||
<syntaxhighlight lang="groovy">def median(Iterable col) { |
|||
def s = col as SortedSet |
|||
if (s == null) return null |
|||
if (s.empty) return 0 |
|||
def n = s.size() |
|||
def m = n.intdiv(2) |
|||
def l = s.collect { it } |
|||
n%2 == 1 ? l[m] : (l[m] + l[m-1])/2 |
|||
}</syntaxhighlight> |
|||
Test: |
|||
<syntaxhighlight lang="groovy">def a = [4.4, 2.3, -1.7, 7.5, 6.6, 0.0, 1.9, 8.2, 9.3, 4.5] |
|||
def sz = a.size() |
|||
(0..sz).each { |
|||
println """${median(a[0..<(sz-it)])} == median(${a[0..<(sz-it)]}) |
|||
${median(a[it..<sz])} == median(${a[it..<sz]})""" |
|||
}</syntaxhighlight> |
|||
Output: |
|||
<pre>4.45 == median([4.4, 2.3, -1.7, 7.5, 6.6, 0.0, 1.9, 8.2, 9.3, 4.5]) |
|||
4.45 == median([4.4, 2.3, -1.7, 7.5, 6.6, 0.0, 1.9, 8.2, 9.3, 4.5]) |
|||
4.4 == median([4.4, 2.3, -1.7, 7.5, 6.6, 0.0, 1.9, 8.2, 9.3]) |
|||
4.5 == median([2.3, -1.7, 7.5, 6.6, 0.0, 1.9, 8.2, 9.3, 4.5]) |
|||
3.35 == median([4.4, 2.3, -1.7, 7.5, 6.6, 0.0, 1.9, 8.2]) |
|||
5.55 == median([-1.7, 7.5, 6.6, 0.0, 1.9, 8.2, 9.3, 4.5]) |
|||
2.3 == median([4.4, 2.3, -1.7, 7.5, 6.6, 0.0, 1.9]) |
|||
6.6 == median([7.5, 6.6, 0.0, 1.9, 8.2, 9.3, 4.5]) |
|||
3.35 == median([4.4, 2.3, -1.7, 7.5, 6.6, 0.0]) |
|||
5.55 == median([6.6, 0.0, 1.9, 8.2, 9.3, 4.5]) |
|||
4.4 == median([4.4, 2.3, -1.7, 7.5, 6.6]) |
|||
4.5 == median([0.0, 1.9, 8.2, 9.3, 4.5]) |
|||
3.35 == median([4.4, 2.3, -1.7, 7.5]) |
|||
6.35 == median([1.9, 8.2, 9.3, 4.5]) |
|||
2.3 == median([4.4, 2.3, -1.7]) |
|||
8.2 == median([8.2, 9.3, 4.5]) |
|||
3.35 == median([4.4, 2.3]) |
|||
6.9 == median([9.3, 4.5]) |
|||
4.4 == median([4.4]) |
|||
4.5 == median([4.5]) |
|||
0 == median([]) |
|||
0 == median([])</pre> |
|||
=={{header|Haskell}}== |
|||
This uses a quick select algorithm and runs in expected O(n) time. |
|||
<syntaxhighlight lang="haskell">import Data.List (partition) |
|||
nth :: Ord t => [t] -> Int -> t |
|||
nth (x:xs) n |
|||
| k == n = x |
|||
| k > n = nth ys n |
|||
| otherwise = nth zs $ n - k - 1 |
|||
where |
|||
(ys, zs) = partition (< x) xs |
|||
k = length ys |
|||
medianMay :: (Fractional a, Ord a) => [a] -> Maybe a |
|||
medianMay xs |
|||
| n < 1 = Nothing |
|||
| even n = Just ((nth xs (div n 2) + nth xs (div n 2 - 1)) / 2.0) |
|||
| otherwise = Just (nth xs (div n 2)) |
|||
where |
|||
n = length xs |
|||
main :: IO () |
|||
main = |
|||
mapM_ |
|||
(printMay . medianMay) |
|||
[[], [7], [5, 3, 4], [5, 4, 2, 3], [3, 4, 1, -8.4, 7.2, 4, 1, 1.2]] |
|||
where |
|||
printMay = maybe (putStrLn "(not defined)") print</syntaxhighlight> |
|||
{{Out}} |
|||
<pre>(not defined) |
|||
7.0 |
|||
4.0 |
|||
3.5 |
|||
2.1</pre> |
|||
Or {{libheader|hstats}} |
|||
<syntaxhighlight lang="haskell">> Math.Statistics.median [1,9,2,4] |
|||
3.0</syntaxhighlight> |
|||
=={{header|HicEst}}== |
|||
If the input has an even number of elements, median is the mean of the middle two values: |
|||
<syntaxhighlight lang="hicest">REAL :: n=10, vec(n) |
|||
vec = RAN(1) |
|||
SORT(Vector=vec, Sorted=vec) ! in-place Merge-Sort |
|||
IF( MOD(n,2) ) THEN ! odd n |
|||
median = vec( CEILING(n/2) ) |
|||
ELSE |
|||
median = ( vec(n/2) + vec(n/2 + 1) ) / 2 |
|||
ENDIF</syntaxhighlight> |
|||
=={{header|Icon}} and {{header|Unicon}}== |
|||
A quick and dirty solution: |
|||
<syntaxhighlight lang="text">procedure main(args) |
|||
write(median(args)) |
|||
end |
|||
procedure median(A) |
|||
A := sort(A) |
|||
n := *A |
|||
return if n % 2 = 1 then A[n/2+1] |
|||
else (A[n/2]+A[n/2+1])/2.0 | 0 # 0 if empty list |
|||
end</syntaxhighlight> |
|||
Sample outputs: |
|||
<pre>->am 3 1 4 1 5 9 7 6 3 |
|||
4 |
|||
->am 3 1 4 1 5 9 7 6 |
|||
4.5 |
|||
-></pre> |
|||
=={{header|J}}== |
|||
The verb <code>median</code> is available from the <code>stats/base</code> addon and returns the mean of the two middle values for an even number of elements: |
|||
<syntaxhighlight lang="j"> require 'stats/base' |
|||
median 1 9 2 4 |
|||
3</syntaxhighlight> |
|||
The definition given in the addon script is: |
|||
<syntaxhighlight lang="j">midpt=: -:@<:@# |
|||
median=: -:@(+/)@((<. , >.)@midpt { /:~)</syntaxhighlight> |
|||
If, for an even number of elements, both values were desired when those two values are distinct, then the following implementation would suffice: |
|||
<syntaxhighlight lang="j"> median=: ~.@(<. , >.)@midpt { /:~ |
|||
median 1 9 2 4 |
|||
2 4</syntaxhighlight> |
|||
=={{header|Java}}== |
=={{header|Java}}== |
||
{{works with|Java|1.5+}} |
{{works with|Java|1.5+}} |
||
Sorting: |
Sorting: |
||
<syntaxhighlight lang="java"> |
|||
<lang java5>// Note: this function modifies the input list |
|||
double median(List<Double> values) { |
|||
/* copy, as to prevent modifying 'values' */ |
|||
Collections.sort(list); |
|||
List<Double> list = new ArrayList<>(values); |
|||
if(list.size() % 2 == 0){ |
|||
Collections.sort(list); |
|||
return (list.get(list.size() / 2) + list.get(list.size() / 2 - 1)) / 2; |
|||
/* 'mid' will be truncated */ |
|||
} |
|||
int mid = list.size() / 2; |
|||
return switch (list.size() % 2) { |
|||
}</lang> |
|||
case 0 -> { |
|||
double valueA = list.get(mid); |
|||
double valueB = list.get(mid + 1); |
|||
yield (valueA + valueB) / 2; |
|||
} |
|||
case 1 -> list.get(mid); |
|||
default -> 0; |
|||
}; |
|||
} |
|||
</syntaxhighlight> |
|||
{{works with|Java|1.5+}} |
{{works with|Java|1.5+}} |
||
Using priority queue: |
|||
<lang java5>public static double median2(List<Double> list){ |
|||
PriorityQueue<Double> pq = new PriorityQueue<Double>(list); |
|||
int n = list.size(); |
|||
for (int i = 0; i < (n-1)/2; i++) |
|||
pq.poll(); // discard first half |
|||
if (n % 2 != 0) // odd length |
|||
return pq.poll(); |
|||
else |
|||
return (pq.poll() + pq.poll()) / 2.0; |
|||
}</lang> |
|||
Using priority queue (which sorts under the hood): |
|||
=={{header|Mathematica}}== |
|||
<syntaxhighlight lang="java5">public static double median2(List<Double> list) { |
|||
PriorityQueue<Double> pq = new PriorityQueue<Double>(list); |
|||
int n = list.size(); |
|||
for (int i = 0; i < (n - 1) / 2; i++) |
|||
pq.poll(); // discard first half |
|||
if (n % 2 != 0) // odd length |
|||
return pq.poll(); |
|||
else |
|||
return (pq.poll() + pq.poll()) / 2.0; |
|||
}</syntaxhighlight> |
|||
{{works with|Java|1.8+}} |
|||
This version operates on objects rather than primitives and uses abstractions to operate on all of the standard numerics. |
|||
<syntaxhighlight lang="java8"> |
|||
@FunctionalInterface |
|||
interface MedianFinder<T, R> extends Function<Collection<T>, R> { |
|||
@Override |
|||
R apply(Collection<T> data); |
|||
} |
|||
class MedianFinderImpl<T, R> implements MedianFinder<T, R> { |
|||
private final Supplier<R> ifEmpty; |
|||
private final Function<T, R> ifOdd; |
|||
private final Function<List<T>, R> ifEven; |
|||
MedianFinderImpl(Supplier<R> ifEmpty, Function<T, R> ifOdd, Function<List<T>, R> ifEven) { |
|||
this.ifEmpty = ifEmpty; |
|||
this.ifOdd = ifOdd; |
|||
this.ifEven = ifEven; |
|||
} |
|||
@Override |
|||
public R apply(Collection<T> data) { |
|||
return Objects.requireNonNull(data, "data must not be null").isEmpty() |
|||
? ifEmpty.get() |
|||
: (data.size() & 1) == 0 |
|||
? ifEven.apply(data.stream().sorted() |
|||
.skip(data.size() / 2 - 1) |
|||
.limit(2).toList()) |
|||
: ifOdd.apply(data.stream().sorted() |
|||
.skip(data.size() / 2) |
|||
.limit(1).findFirst().get()); |
|||
} |
|||
} |
|||
public class MedianOf { |
|||
private static final MedianFinder<Integer, Integer> INTEGERS = new MedianFinderImpl<>(() -> 0, n -> n, pair -> (pair.get(0) + pair.get(1)) / 2); |
|||
private static final MedianFinder<Integer, Float> INTEGERS_AS_FLOAT = new MedianFinderImpl<>(() -> 0f, n -> n * 1f, pair -> (pair.get(0) + pair.get(1)) / 2f); |
|||
private static final MedianFinder<Integer, Double> INTEGERS_AS_DOUBLE = new MedianFinderImpl<>(() -> 0d, n -> n * 1d, pair -> (pair.get(0) + pair.get(1)) / 2d); |
|||
private static final MedianFinder<Float, Float> FLOATS = new MedianFinderImpl<>(() -> 0f, n -> n, pair -> (pair.get(0) + pair.get(1)) / 2); |
|||
private static final MedianFinder<Double, Double> DOUBLES = new MedianFinderImpl<>(() -> 0d, n -> n, pair -> (pair.get(0) + pair.get(1)) / 2); |
|||
private static final MedianFinder<BigInteger, BigInteger> BIG_INTEGERS = new MedianFinderImpl<>(() -> BigInteger.ZERO, n -> n, pair -> pair.get(0).add(pair.get(1)).divide(BigInteger.TWO)); |
|||
private static final MedianFinder<BigInteger, BigDecimal> BIG_INTEGERS_AS_BIG_DECIMAL = new MedianFinderImpl<>(() -> BigDecimal.ZERO, BigDecimal::new, pair -> new BigDecimal(pair.get(0).add(pair.get(1))).divide(BigDecimal.valueOf(2), RoundingMode.FLOOR)); |
|||
private static final MedianFinder<BigDecimal, BigDecimal> BIG_DECIMALS = new MedianFinderImpl<>(() -> BigDecimal.ZERO, n -> n, pair -> pair.get(0).add(pair.get(1)).divide(BigDecimal.valueOf(2), RoundingMode.FLOOR)); |
|||
public static Integer integers(Collection<Integer> integerCollection) { return INTEGERS.apply(integerCollection); } |
|||
public static Float integersAsFloat(Collection<Integer> integerCollection) { return INTEGERS_AS_FLOAT.apply(integerCollection); } |
|||
public static Double integersAsDouble(Collection<Integer> integerCollection) { return INTEGERS_AS_DOUBLE.apply(integerCollection); } |
|||
public static Float floats(Collection<Float> floatCollection) { return FLOATS.apply(floatCollection); } |
|||
public static Double doubles(Collection<Double> doubleCollection) { return DOUBLES.apply(doubleCollection); } |
|||
public static BigInteger bigIntegers(Collection<BigInteger> bigIntegerCollection) { return BIG_INTEGERS.apply(bigIntegerCollection); } |
|||
public static BigDecimal bigIntegersAsBigDecimal(Collection<BigInteger> bigIntegerCollection) { return BIG_INTEGERS_AS_BIG_DECIMAL.apply(bigIntegerCollection); } |
|||
public static BigDecimal bigDecimals(Collection<BigDecimal> bigDecimalCollection) { return BIG_DECIMALS.apply(bigDecimalCollection); } |
|||
} |
|||
</syntaxhighlight> |
|||
=={{header|JavaScript}}== |
|||
===ES5=== |
|||
<syntaxhighlight lang="javascript">function median(ary) { |
|||
if (ary.length == 0) |
|||
return null; |
|||
ary.sort(function (a,b){return a - b}) |
|||
var mid = Math.floor(ary.length / 2); |
|||
if ((ary.length % 2) == 1) // length is odd |
|||
return ary[mid]; |
|||
else |
|||
return (ary[mid - 1] + ary[mid]) / 2; |
|||
} |
|||
median([]); // null |
|||
median([5,3,4]); // 4 |
|||
median([5,4,2,3]); // 3.5 |
|||
median([3,4,1,-8.4,7.2,4,1,1.2]); // 2.1</syntaxhighlight> |
|||
===ES6=== |
|||
Using a quick select algorithm |
|||
{{Trans|Haskell}} |
|||
<syntaxhighlight lang="javascript">(() => { |
|||
'use strict'; |
|||
// median :: [Num] -> Num |
|||
function median(xs) { |
|||
// nth :: [Num] -> Int -> Maybe Num |
|||
let nth = (xxs, n) => { |
|||
if (xxs.length > 0) { |
|||
let [x, xs] = uncons(xxs), |
|||
[ys, zs] = partition(y => y < x, xs), |
|||
k = ys.length; |
|||
return k === n ? x : ( |
|||
k > n ? nth(ys, n) : nth(zs, n - k - 1) |
|||
); |
|||
} else return undefined; |
|||
}, |
|||
n = xs.length; |
|||
return even(n) ? ( |
|||
(nth(xs, div(n, 2)) + nth(xs, div(n, 2) - 1)) / 2 |
|||
) : nth(xs, div(n, 2)); |
|||
} |
|||
// GENERIC |
|||
// partition :: (a -> Bool) -> [a] -> ([a], [a]) |
|||
let partition = (p, xs) => |
|||
xs.reduce((a, x) => |
|||
p(x) ? [a[0].concat(x), a[1]] : [a[0], a[1].concat(x)], [ |
|||
[], |
|||
[] |
|||
]), |
|||
// uncons :: [a] -> Maybe (a, [a]) |
|||
uncons = xs => xs.length ? [xs[0], xs.slice(1)] : undefined, |
|||
// even :: Integral a => a -> Bool |
|||
even = n => n % 2 === 0, |
|||
// div :: Num -> Num -> Int |
|||
div = (x, y) => Math.floor(x / y); |
|||
return [ |
|||
[], |
|||
[5, 3, 4], |
|||
[5, 4, 2, 3], |
|||
[3, 4, 1, -8.4, 7.2, 4, 1, 1.2] |
|||
].map(median); |
|||
})();</syntaxhighlight> |
|||
{{Out}} |
|||
<syntaxhighlight lang="javascript">[ |
|||
null, |
|||
4, |
|||
3.5, |
|||
2.1 |
|||
]</syntaxhighlight> |
|||
=={{header|jq}}== |
|||
<syntaxhighlight lang="jq">def median: |
|||
length as $length |
|||
| sort as $s |
|||
| if $length == 0 then null |
|||
else ($length / 2 | floor) as $l2 |
|||
| if ($length % 2) == 0 then |
|||
($s[$l2 - 1] + $s[$l2]) / 2 |
|||
else $s[$l2] |
|||
end |
|||
end ;</syntaxhighlight>This definition can be used in a jq program, but to illustrate how it can be used as a command line filter, suppose the definition and the program '''median''' are in a file named median.jq, and that the file in.dat contains a sequence of arrays, such as <syntaxhighlight lang="sh">[4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2] |
|||
[4.1, 7.2, 1.7, 9.3, 4.4, 3.2]</syntaxhighlight>Then invoking the jq program yields a stream of values:<syntaxhighlight lang="sh">$ jq -f median.jq in.dat |
|||
4.4 |
|||
4.25</syntaxhighlight> |
|||
=={{header|Julia}}== |
|||
Julia has a built-in median() function |
|||
<syntaxhighlight lang="julia">using Statistics |
|||
function median2(n) |
|||
s = sort(n) |
|||
len = length(n) |
|||
if len % 2 == 0 |
|||
return (s[floor(Int, len / 2) + 1] + s[floor(Int, len / 2)]) / 2 |
|||
else |
|||
return s[floor(Int, len / 2) + 1] |
|||
end |
|||
end |
|||
a = [4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2] |
|||
b = [4.1, 7.2, 1.7, 9.3, 4.4, 3.2] |
|||
@show a b median2(a) median(a) median2(b) median(b) </syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
a = [4.1,5.6,7.2,1.7,9.3,4.4,3.2] |
|||
b = [4.1,7.2,1.7,9.3,4.4,3.2] |
|||
median2(a) = 4.4 |
|||
median(a) = 4.4 |
|||
median2(b) = 4.25 |
|||
median(b) = 4.25 |
|||
</pre> |
|||
=={{header|K}}== |
|||
<syntaxhighlight lang="k"> |
|||
med:{a:x@<x; i:(#a)%2; :[(#a)!2; a@i; {(+/x)%#x} a@i,i-1]} |
|||
v:10*6 _draw 0 |
|||
v |
|||
5.961475 2.025856 7.262835 1.814272 2.281911 4.854716 |
|||
med[v] |
|||
3.568313 |
|||
med[1_ v] |
|||
2.281911 |
|||
</syntaxhighlight> |
|||
An alternate solution which works in the oK implementation using the same dataset v from above and shows both numbers around the median point on even length datasets would be: |
|||
<syntaxhighlight lang="k"> |
|||
med:{a:x@<x; i:_(#a)%2 |
|||
$[2!#a; a@i; |a@i,i-1]} |
|||
med[v] |
|||
2.2819 4.8547 |
|||
</syntaxhighlight> |
|||
=={{header|Kotlin}}== |
|||
{{works with|Kotlin|1.0+}} |
|||
<syntaxhighlight lang="scala">fun median(l: List<Double>) = l.sorted().let { (it[it.size / 2] + it[(it.size - 1) / 2]) / 2 } |
|||
fun main(args: Array<String>) { |
|||
median(listOf(5.0, 3.0, 4.0)).let { println(it) } // 4 |
|||
median(listOf(5.0, 4.0, 2.0, 3.0)).let { println(it) } // 3.5 |
|||
median(listOf(3.0, 4.0, 1.0, -8.4, 7.2, 4.0, 1.0, 1.2)).let { println(it) } // 2.1 |
|||
}</syntaxhighlight> |
|||
=={{header|Lambdatalk}}== |
|||
{{trans|11l}} |
|||
<syntaxhighlight lang="scheme"> |
|||
{def median |
|||
{lambda {:s} |
|||
{let { {:a {A.sort! < {A.new :s}}} |
|||
{:len {S.length :s}} |
|||
} {* 0.5 {+ {A.get {floor {/ {- :len 1} 2}} :a} |
|||
{A.get {floor {/ :len 2}} :a} }} }}} |
|||
-> median |
|||
{median 4.1 5.6 7.2 1.7 9.3 4.4 3.2} |
|||
-> 4.4 |
|||
{median 4.1 7.2 1.7 9.3 4.4 3.2} |
|||
-> 4.25 |
|||
</syntaxhighlight> |
|||
=={{header|Lasso}}== |
|||
can't use Lasso's built in median method because |
|||
that takes 3 values, not an array of indeterminate length |
|||
Lasso's built in function is "median( value_1, value_2, value_3 )" |
|||
<syntaxhighlight lang="lasso">define median_ext(a::array) => { |
|||
#a->sort |
|||
if(#a->size % 2) => { |
|||
// odd numbered element array, pick middle |
|||
return #a->get(#a->size / 2 + 1) |
|||
else |
|||
// even number elements in array |
|||
return (#a->get(#a->size / 2) + #a->get(#a->size / 2 + 1)) / 2.0 |
|||
} |
|||
} |
|||
median_ext(array(3,2,7,6)) // 4.5 |
|||
median_ext(array(3,2,9,7,6)) // 6</syntaxhighlight> |
|||
=={{header|Liberty BASIC}}== |
|||
<syntaxhighlight lang="lb"> |
|||
dim a( 100), b( 100) ' assumes we will not have vectors of more terms... |
|||
a$ ="4.1,5.6,7.2,1.7,9.3,4.4,3.2" |
|||
print "Median is "; median( a$) ' 4.4 7 terms |
|||
print |
|||
a$ ="4.1,7.2,1.7,9.3,4.4,3.2" |
|||
print "Median is "; median( a$) ' 4.25 6 terms |
|||
print |
|||
a$ ="4.1,4,1.2,6.235,7868.33" ' 4.1 |
|||
print "Median of "; a$; " is "; median( a$) |
|||
print |
|||
a$ ="1,5,3,2,4" ' 3 |
|||
print "Median of "; a$; " is "; median( a$) |
|||
print |
|||
a$ ="1,5,3,6,4,2" ' 3.5 |
|||
print "Median of "; a$; " is "; median( a$) |
|||
print |
|||
a$ ="4.4,2.3,-1.7,7.5,6.6,0.0,1.9,8.2,9.3,4.5" ' 4.45 |
|||
print "Median of "; a$; " is "; median( a$) |
|||
end |
|||
function median( a$) |
|||
i =1 |
|||
do |
|||
v$ =word$( a$, i, ",") |
|||
if v$ ="" then exit do |
|||
print v$, |
|||
a( i) =val( v$) |
|||
i =i +1 |
|||
loop until 0 |
|||
print |
|||
sort a(), 1, i -1 |
|||
for j =1 to i -1 |
|||
print a( j), |
|||
next j |
|||
print |
|||
middle =( i -1) /2 |
|||
intmiddle =int( middle) |
|||
if middle <>intmiddle then median= a( 1 +intmiddle) else median =( a( intmiddle) +a( intmiddle +1)) /2 |
|||
end function |
|||
</syntaxhighlight> |
|||
<pre> |
|||
4.1 5.6 7.2 1.7 9.3 4.4 3.2 |
|||
Median is 4.4 |
|||
4.1 7.2 1.7 9.3 4.4 3.2 |
|||
Median is 4.25 |
|||
4.1 4 1.2 6.235 7868.33 |
|||
Median of 4.1,4,1.2,6.235,7868.33 is 4.1 |
|||
1 5 3 2 4 |
|||
Median of 1,5,3,2,4 is 3 |
|||
1 5 3 6 4 2 |
|||
Median of 1,5,3,6,4,2 is 3.5 |
|||
4.4 2.3 -1.7 7.5 6.6 0.0 1.9 8.2 9.3 4.5 |
|||
Median of 4.4,2.3,-1.7,7.5,6.6,0.0,1.9,8.2,9.3,4.5 is 4.45 |
|||
</pre> |
|||
=={{header|Lingo}}== |
|||
<syntaxhighlight lang="lingo">on median (numlist) |
|||
-- numlist = numlist.duplicate() -- if input list should not be altered |
|||
numlist.sort() |
|||
if numlist.count mod 2 then |
|||
return numlist[numlist.count/2+1] |
|||
else |
|||
return (numlist[numlist.count/2]+numlist[numlist.count/2+1])/2.0 |
|||
end if |
|||
end</syntaxhighlight> |
|||
=={{header|LiveCode}}== |
|||
LC has median as a built-in function |
|||
<syntaxhighlight lang="livecode">put median("4.1,5.6,7.2,1.7,9.3,4.4,3.2") & "," & median("4.1,7.2,1.7,9.3,4.4,3.2") |
|||
returns 4.4, 4.25</syntaxhighlight> |
|||
To make our own, we need own own floor function first |
|||
<syntaxhighlight lang="livecode">function floor n |
|||
if n < 0 then |
|||
return (trunc(n) - 1) |
|||
else |
|||
return trunc(n) |
|||
end if |
|||
end floor |
|||
function median2 x |
|||
local n, m |
|||
set itemdelimiter to comma |
|||
sort items of x ascending numeric |
|||
put the number of items of x into n |
|||
put floor(n / 2) into m |
|||
if n mod 2 is 0 then |
|||
return (item m of x + item (m + 1) of x) / 2 |
|||
else |
|||
return item (m + 1) of x |
|||
end if |
|||
end median2 |
|||
returns the same as the built-in median, viz. |
|||
put median2("4.1,5.6,7.2,1.7,9.3,4.4,3.2") & "," & median2("4.1,7.2,1.7,9.3,4.4,3.2") |
|||
4.4,4.25</syntaxhighlight> |
|||
=={{header|LSL}}== |
|||
<syntaxhighlight lang="lsl">integer MAX_ELEMENTS = 10; |
|||
integer MAX_VALUE = 100; |
|||
default { |
|||
state_entry() { |
|||
list lst = []; |
|||
integer x = 0; |
|||
for(x=0 ; x<MAX_ELEMENTS ; x++) { |
|||
lst += llFrand(MAX_VALUE); |
|||
} |
|||
llOwnerSay("lst=["+llList2CSV(lst)+"]"); |
|||
llOwnerSay("Geometric Mean: "+(string)llListStatistics(LIST_STAT_GEOMETRIC_MEAN, lst)); |
|||
llOwnerSay(" Max: "+(string)llListStatistics(LIST_STAT_MAX, lst)); |
|||
llOwnerSay(" Mean: "+(string)llListStatistics(LIST_STAT_MEAN, lst)); |
|||
llOwnerSay(" Median: "+(string)llListStatistics(LIST_STAT_MEDIAN, lst)); |
|||
llOwnerSay(" Min: "+(string)llListStatistics(LIST_STAT_MIN, lst)); |
|||
llOwnerSay(" Num Count: "+(string)llListStatistics(LIST_STAT_NUM_COUNT, lst)); |
|||
llOwnerSay(" Range: "+(string)llListStatistics(LIST_STAT_RANGE, lst)); |
|||
llOwnerSay(" Std Dev: "+(string)llListStatistics(LIST_STAT_STD_DEV, lst)); |
|||
llOwnerSay(" Sum: "+(string)llListStatistics(LIST_STAT_SUM, lst)); |
|||
llOwnerSay(" Sum Squares: "+(string)llListStatistics(LIST_STAT_SUM_SQUARES, lst)); |
|||
} |
|||
}</syntaxhighlight> |
|||
Output: |
|||
<pre> |
|||
lst=[23.815209, 85.890704, 10.811144, 31.522696, 54.619416, 12.211729, 42.964463, 87.367889, 7.106129, 18.711078] |
|||
Geometric Mean: 27.325070 |
|||
Max: 87.367889 |
|||
Mean: 37.502046 |
|||
Median: 27.668953 |
|||
Min: 7.106129 |
|||
Num Count: 10.000000 |
|||
Range: 80.261761 |
|||
Std Dev: 29.819840 |
|||
Sum: 375.020458 |
|||
Sum Squares: 22067.040048 |
|||
</pre> |
|||
=={{header|Lua}}== |
|||
<syntaxhighlight lang="lua">function median (numlist) |
|||
if type(numlist) ~= 'table' then return numlist end |
|||
table.sort(numlist) |
|||
if #numlist %2 == 0 then return (numlist[#numlist/2] + numlist[#numlist/2+1]) / 2 end |
|||
return numlist[math.ceil(#numlist/2)] |
|||
end |
|||
print(median({4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2})) |
|||
print(median({4.1, 7.2, 1.7, 9.3, 4.4, 3.2}))</syntaxhighlight> |
|||
=={{header|Maple}}== |
|||
=== Builtin === |
|||
This works for numeric lists or arrays, and is designed for large data sets. |
|||
<syntaxhighlight lang="maple"> |
|||
> Statistics:-Median( [ 1, 5, 3, 2, 4 ] ); |
|||
3. |
|||
> Statistics:-Median( [ 1, 5, 3, 6, 2, 4 ] ); |
|||
3.50000000000000 |
|||
</syntaxhighlight> |
|||
=== Using a sort === |
|||
This solution can handle exact numeric inputs. Instead of inputting a container of some kind, it simply finds the median of its arguments. |
|||
<syntaxhighlight lang="maple"> |
|||
median1 := proc() |
|||
local L := sort( [ args ] ); |
|||
( L[ iquo( 1 + nargs, 2 ) ] + L[ 1 + iquo( nargs, 2 ) ] ) / 2 |
|||
end proc: |
|||
</syntaxhighlight> |
|||
For example: |
|||
<syntaxhighlight lang="maple"> |
|||
> median1( 1, 5, 3, 2, 4 ); # 3 |
|||
3 |
|||
> median1( 1, 5, 3, 6, 4, 2 ); # 7/2 |
|||
7/2 |
|||
</syntaxhighlight> |
|||
=={{header|Mathematica}} / {{header|Wolfram Language}}== |
|||
Built-in function: |
Built-in function: |
||
<syntaxhighlight lang="mathematica">Median[{1, 5, 3, 2, 4}] |
|||
<lang Mathematica> |
|||
Median[{1, 5, 3, 6, 4, 2}]</syntaxhighlight> |
|||
{{out}} |
|||
Median[{1, 5, 3, 6, 4, 2}] |
|||
< |
<pre>3 |
||
7/2</pre> |
|||
gives back: |
|||
<lang Mathematica> |
|||
3 |
|||
7/2 |
|||
</lang> |
|||
Custom function: |
Custom function: |
||
<syntaxhighlight lang="mathematica">mymedian[x_List]:=Module[{t=Sort[x],L=Length[x]}, |
|||
<lang Mathematica> |
|||
If[Mod[L,2]==0, |
|||
mymedian[x_List]:=Module[{t=Sort[x],L=Length[x]}, |
|||
(t[[L/2]]+t[[L/2+1]])/2 |
|||
, |
|||
(t[[L/2]]+t[[L/2+1]])/2 |
|||
t[[(L+1)/2]] |
|||
, |
|||
t[[(L+1)/2]] |
|||
] |
|||
] |
] |
||
]</syntaxhighlight> |
|||
</lang> |
|||
Example of custom function: |
Example of custom function: |
||
<syntaxhighlight lang="mathematica">mymedian[{1, 5, 3, 2, 4}] |
|||
<lang Mathematica> |
|||
mymedian[{1, 5, 3, 6, 4, 2}]</syntaxhighlight> |
|||
{{out}} |
|||
mymedian[{1, 5, 3, 6, 4, 2}] |
|||
< |
<pre>3 |
||
7/2</pre> |
|||
gives back: |
|||
<lang Mathematica> |
|||
3 |
|||
7/2 |
|||
</lang> |
|||
=={{header|MATLAB}}== |
|||
If the input has an even number of elements, function returns the mean of the middle two values: |
|||
<syntaxhighlight lang="matlab">function medianValue = findmedian(setOfValues) |
|||
medianValue = median(setOfValues); |
|||
end</syntaxhighlight> |
|||
=={{header|Maxima}}== |
|||
<syntaxhighlight lang="maxima">/* built-in */ |
|||
median([41, 56, 72, 17, 93, 44, 32]); /* 44 */ |
|||
median([41, 72, 17, 93, 44, 32]); /* 85/2 */</syntaxhighlight> |
|||
=={{header|min}}== |
|||
<syntaxhighlight lang="min">('> sort med) ^median |
|||
(4.1 5.6 7.2 1.7 9.3 4.4 3.2) median puts! |
|||
(4.1 7.2 1.7 9.3 4.4 3.2) median puts!</syntaxhighlight> |
|||
{{out}} |
|||
<pre>4.4 |
|||
4.25</pre> |
|||
=={{header|MiniScript}}== |
|||
<syntaxhighlight lang="miniscript">list.median = function() |
|||
self.sort |
|||
m = floor(self.len/2) |
|||
if self.len % 2 then return self[m] |
|||
return (self[m] + self[m-1]) * 0.5 |
|||
end function |
|||
print [41, 56, 72, 17, 93, 44, 32].median |
|||
print [41, 72, 17, 93, 44, 32].median</syntaxhighlight> |
|||
{{out}} |
|||
<pre>44 |
|||
42.5</pre> |
|||
=={{header|MUMPS}}== |
|||
<syntaxhighlight lang="mumps">MEDIAN(X) |
|||
;X is assumed to be a list of numbers separated by "^" |
|||
;I is a loop index |
|||
;L is the length of X |
|||
;Y is a new array |
|||
QUIT:'$DATA(X) "No data" |
|||
QUIT:X="" "Empty Set" |
|||
NEW I,ODD,L,Y |
|||
SET L=$LENGTH(X,"^"),ODD=L#2,I=1 |
|||
;The values in the vector are used as indices for a new array Y, which sorts them |
|||
FOR QUIT:I>L SET Y($PIECE(X,"^",I))=1,I=I+1 |
|||
;Go to the median index, or the lesser of the middle if there is an even number of elements |
|||
SET J="" FOR I=1:1:$SELECT(ODD:L\2+1,'ODD:L/2) SET J=$ORDER(Y(J)) |
|||
QUIT $SELECT(ODD:J,'ODD:(J+$ORDER(Y(J)))/2) |
|||
</syntaxhighlight> |
|||
<pre>USER>W $$MEDIAN^ROSETTA("-1.3^2.43^3.14^17^2E-3") |
|||
3.14 |
|||
USER>W $$MEDIAN^ROSETTA("-1.3^2.43^3.14^17^2E-3^4") |
|||
3.57 |
|||
USER>W $$MEDIAN^ROSETTA("") |
|||
Empty Set |
|||
USER>W $$MEDIAN^ROSETTA |
|||
No data</pre> |
|||
=={{header|Nanoquery}}== |
|||
{{trans|Python}} |
|||
<syntaxhighlight lang="nanoquery">import sort |
|||
def median(aray) |
|||
srtd = sort(aray) |
|||
alen = len(srtd) |
|||
return 0.5*( srtd[int(alen-1/2)] + srtd[int(alen/2)]) |
|||
end |
|||
a = {4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2} |
|||
println a + " " + median(a) |
|||
a = {4.1, 7.2, 1.7, 9.3, 4.4, 3.2} |
|||
println a + " " + median(a)</syntaxhighlight> |
|||
=={{header|NetRexx}}== |
|||
{{trans|Java}} |
|||
<syntaxhighlight lang="netrexx">/* NetRexx */ |
|||
options replace format comments java crossref symbols nobinary |
|||
class RAvgMedian00 public |
|||
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|||
method median(lvector = java.util.List) public static returns Rexx |
|||
cvector = ArrayList(lvector) -- make a copy of input to ensure it's contents are preserved |
|||
Collections.sort(cvector, RAvgMedian00.RexxComparator()) |
|||
kVal = ((Rexx cvector.get(cvector.size() % 2)) + (Rexx cvector.get((cvector.size() - 1) % 2))) / 2 |
|||
return kVal |
|||
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|||
method median(rvector = Rexx[]) public static returns Rexx |
|||
return median(ArrayList(Arrays.asList(rvector))) |
|||
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|||
method show_median(lvector = java.util.List) public static returns Rexx |
|||
mVal = median(lvector) |
|||
say 'Meadian:' mVal.format(10, 6, 3, 6, 's')', Vector:' (Rexx lvector).space(0) |
|||
return mVal |
|||
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|||
method show_median(rvector = Rexx[]) public static returns Rexx |
|||
return show_median(ArrayList(Arrays.asList(rvector))) |
|||
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|||
method run_samples() public static |
|||
show_median([Rexx 10.0]) -- 10.0 |
|||
show_median([Rexx 10.0, 9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0]) -- 5.5 |
|||
show_median([Rexx 9, 8, 7, 6, 5, 4, 3, 2, 1]) -- 5.0 |
|||
show_median([Rexx 1.0, 9, 2.0, 4.0]) -- 3.0 |
|||
show_median([Rexx 3.0, 1, 4, 1.0, 5.0, 9, 7.0, 6.0]) -- 4.5 |
|||
show_median([Rexx 3, 4, 1, -8.4, 7.2, 4, 1, 1.2]) -- 2.1 |
|||
show_median([Rexx -1.2345678e+99, 2.3e+700]) -- 1.15e+700 |
|||
show_median([Rexx 4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2]) -- 4.4 |
|||
show_median([Rexx 4.1, 7.2, 1.7, 9.3, 4.4, 3.2]) -- 4.25 |
|||
show_median([Rexx 28.207, 74.916, 51.695, 72.486, 51.118, 3.241, 73.807]) -- 51.695 |
|||
show_median([Rexx 27.984, 89.172, 0.250, 66.316, 41.805, 60.043]) -- 50.924 |
|||
show_median([Rexx 5.1, 2.6, 6.2, 8.8, 4.6, 4.1]) -- 4.85 |
|||
show_median([Rexx 5.1, 2.6, 8.8, 4.6, 4.1]) -- 4.6 |
|||
show_median([Rexx 4.4, 2.3, -1.7, 7.5, 6.6, 0.0, 1.9, 8.2, 9.3, 4.5]) -- 4.45 |
|||
show_median([Rexx 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0.11]) -- 3.0 |
|||
show_median([Rexx 10, 20, 30, 40, 50, -100, 4.7, -11e+2]) -- 15.0 |
|||
show_median([Rexx 9.3, -2.0, 4.0, 7.3, 8.1, 4.1, -6.3, 4.2, -1.0, -8.4]) -- 4.05 |
|||
show_median([Rexx 8.3, -3.6, 5.7, 2.3, 9.3, 5.4, -2.3, 6.3, 9.9]) -- 5.7 |
|||
return |
|||
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|||
method main(args = String[]) public static |
|||
run_samples() |
|||
return |
|||
-- ============================================================================= |
|||
class RAvgMedian00.RexxComparator implements Comparator |
|||
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|||
method compare(i1=Object, i2=Object) public returns int |
|||
i = Rexx i1 |
|||
j = Rexx i2 |
|||
if i < j then return -1 |
|||
if i > j then return +1 |
|||
else return 0 |
|||
</syntaxhighlight> |
|||
'''Output:''' |
|||
<pre> |
|||
Meadian: 10.000000 , Vector: [10.0] |
|||
Meadian: 5.500000 , Vector: [10.0,9.0,8.0,7.0,6.0,5.0,4.0,3.0,2.0,1.0] |
|||
Meadian: 5.000000 , Vector: [9,8,7,6,5,4,3,2,1] |
|||
Meadian: 3.000000 , Vector: [1.0,9,2.0,4.0] |
|||
Meadian: 4.500000 , Vector: [3.0,1,4,1.0,5.0,9,7.0,6.0] |
|||
Meadian: 2.100000 , Vector: [3,4,1,-8.4,7.2,4,1,1.2] |
|||
Meadian: 1.150000E+700, Vector: [-1.2345678E+99,2.3e+700] |
|||
Meadian: 4.400000 , Vector: [4.1,5.6,7.2,1.7,9.3,4.4,3.2] |
|||
Meadian: 4.250000 , Vector: [4.1,7.2,1.7,9.3,4.4,3.2] |
|||
Meadian: 51.695000 , Vector: [28.207,74.916,51.695,72.486,51.118,3.241,73.807] |
|||
Meadian: 50.924000 , Vector: [27.984,89.172,0.250,66.316,41.805,60.043] |
|||
Meadian: 4.850000 , Vector: [5.1,2.6,6.2,8.8,4.6,4.1] |
|||
Meadian: 4.600000 , Vector: [5.1,2.6,8.8,4.6,4.1] |
|||
Meadian: 4.450000 , Vector: [4.4,2.3,-1.7,7.5,6.6,0.0,1.9,8.2,9.3,4.5] |
|||
Meadian: 3.000000 , Vector: [10,9,8,7,6,5,4,3,2,1,0,0,0,0,0.11] |
|||
Meadian: 15.000000 , Vector: [10,20,30,40,50,-100,4.7,-1100] |
|||
Meadian: 4.050000 , Vector: [9.3,-2.0,4.0,7.3,8.1,4.1,-6.3,4.2,-1.0,-8.4] |
|||
Meadian: 5.700000 , Vector: [8.3,-3.6,5.7,2.3,9.3,5.4,-2.3,6.3,9.9] |
|||
</pre> |
|||
=={{header|NewLISP}}== |
|||
<syntaxhighlight lang="newlisp">; median.lsp |
|||
; oofoe 2012-01-25 |
|||
(define (median lst) |
|||
(sort lst) ; Sorts in place. |
|||
(if (empty? lst) |
|||
nil |
|||
(letn ((n (length lst)) |
|||
(h (/ (- n 1) 2))) |
|||
(if (zero? (mod n 2)) |
|||
(div (add (lst h) (lst (+ h 1))) 2) |
|||
(lst h)) |
|||
))) |
|||
(define (test lst) (println lst " -> " (median lst))) |
|||
(test '()) |
|||
(test '(5 3 4)) |
|||
(test '(5 4 2 3)) |
|||
(test '(3 4 1 -8.4 7.2 4 1 1.2)) |
|||
(exit)</syntaxhighlight> |
|||
Sample output: |
|||
<pre>() -> nil |
|||
(5 3 4) -> 4 |
|||
(5 4 2 3) -> 3.5 |
|||
(3 4 1 -8.4 7.2 4 1 1.2) -> 2.1 |
|||
</pre> |
|||
=={{header|Nim}}== |
|||
{{trans|Python}} |
|||
<syntaxhighlight lang="nim">import algorithm, strutils |
|||
proc median(xs: seq[float]): float = |
|||
var ys = xs |
|||
sort(ys, system.cmp[float]) |
|||
0.5 * (ys[ys.high div 2] + ys[ys.len div 2]) |
|||
var a = @[4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2] |
|||
echo formatFloat(median(a), precision = 0) |
|||
a = @[4.1, 7.2, 1.7, 9.3, 4.4, 3.2] |
|||
echo formatFloat(median(a), precision = 0)</syntaxhighlight> |
|||
Example Output: |
|||
4.4 |
|||
4.25 |
|||
=={{header|Oberon-2}}== |
|||
Oxford Oberon-2 |
|||
<syntaxhighlight lang="oberon2"> |
|||
MODULE Median; |
|||
IMPORT Out; |
|||
CONST |
|||
MAXSIZE = 100; |
|||
PROCEDURE Partition(VAR a: ARRAY OF REAL; left, right: INTEGER): INTEGER; |
|||
VAR |
|||
pValue,aux: REAL; |
|||
store,i,pivot: INTEGER; |
|||
BEGIN |
|||
pivot := right; |
|||
pValue := a[pivot]; |
|||
aux := a[right];a[right] := a[pivot];a[pivot] := aux; (* a[pivot] <-> a[right] *) |
|||
store := left; |
|||
FOR i := left TO right -1 DO |
|||
IF a[i] <= pValue THEN |
|||
aux := a[store];a[store] := a[i];a[i]:=aux; |
|||
INC(store) |
|||
END |
|||
END; |
|||
aux := a[right];a[right] := a[store]; a[store] := aux; |
|||
RETURN store |
|||
END Partition; |
|||
(* QuickSelect algorithm *) |
|||
PROCEDURE Select(a: ARRAY OF REAL; left,right,k: INTEGER;VAR r: REAL); |
|||
VAR |
|||
pIndex, pDist : INTEGER; |
|||
BEGIN |
|||
IF left = right THEN r := a[left]; RETURN END; |
|||
pIndex := Partition(a,left,right); |
|||
pDist := pIndex - left + 1; |
|||
IF pDist = k THEN |
|||
r := a[pIndex];RETURN |
|||
ELSIF k < pDist THEN |
|||
Select(a,left, pIndex - 1, k, r) |
|||
ELSE |
|||
Select(a,pIndex + 1, right, k - pDist, r) |
|||
END |
|||
END Select; |
|||
PROCEDURE Median(a: ARRAY OF REAL;left,right: INTEGER): REAL; |
|||
VAR |
|||
idx,len : INTEGER; |
|||
r1,r2 : REAL; |
|||
BEGIN |
|||
len := right - left + 1; |
|||
idx := len DIV 2 + 1; |
|||
r1 := 0.0;r2 := 0.0; |
|||
Select(a,left,right,idx,r1); |
|||
IF ODD(len) THEN RETURN r1 END; |
|||
Select(a,left,right,idx - 1,r2); |
|||
RETURN (r1 + r2) / 2; |
|||
END Median; |
|||
VAR |
|||
ary: ARRAY MAXSIZE OF REAL; |
|||
r: REAL; |
|||
BEGIN |
|||
r := 0.0; |
|||
Out.Fixed(Median(ary,0,0),4,2);Out.Ln; (* empty *) |
|||
ary[0] := 5; |
|||
ary[1] := 3; |
|||
ary[2] := 4; |
|||
Out.Fixed(Median(ary,0,2),4,2);Out.Ln; |
|||
ary[0] := 5; |
|||
ary[1] := 4; |
|||
ary[2] := 2; |
|||
ary[3] := 3; |
|||
Out.Fixed(Median(ary,0,3),4,2);Out.Ln; |
|||
ary[0] := 3; |
|||
ary[1] := 4; |
|||
ary[2] := 1; |
|||
ary[3] := -8.4; |
|||
ary[4] := 7.2; |
|||
ary[5] := 4; |
|||
ary[6] := 1; |
|||
ary[7] := 1.2; |
|||
Out.Fixed(Median(ary,0,7),4,2);Out.Ln; |
|||
END Median. |
|||
</syntaxhighlight> |
|||
Output: |
|||
<pre> |
|||
0.00 |
|||
4.00 |
|||
3.50 |
|||
2.10 |
|||
</pre> |
|||
=={{header|Objeck}}== |
|||
<syntaxhighlight lang="objeck"> |
|||
use Structure; |
|||
bundle Default { |
|||
class Median { |
|||
function : Main(args : String[]) ~ Nil { |
|||
numbers := FloatVector->New([4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2]); |
|||
DoMedian(numbers)->PrintLine(); |
|||
numbers := FloatVector->New([4.1, 7.2, 1.7, 9.3, 4.4, 3.2]); |
|||
DoMedian(numbers)->PrintLine(); |
|||
} |
|||
function : native : DoMedian(numbers : FloatVector) ~ Float { |
|||
if(numbers->Size() = 0) { |
|||
return 0.0; |
|||
} |
|||
else if(numbers->Size() = 1) { |
|||
return numbers->Get(0); |
|||
}; |
|||
numbers->Sort(); |
|||
i := numbers->Size() / 2; |
|||
if(numbers->Size() % 2 = 0) { |
|||
return (numbers->Get(i - 1) + numbers->Get(i)) / 2.0; |
|||
}; |
|||
return numbers->Get(i); |
|||
} |
|||
} |
|||
} |
|||
</syntaxhighlight> |
|||
=={{header|OCaml}}== |
=={{header|OCaml}}== |
||
< |
<syntaxhighlight lang="ocaml">(* note: this modifies the input array *) |
||
let median array = |
|||
let len = Array.length array in |
let len = Array.length array in |
||
Array.sort compare array; |
Array.sort compare array; |
||
Line 202: | Line 4,326: | ||
median a;; |
median a;; |
||
let a = [|4.1; 7.2; 1.7; 9.3; 4.4; 3.2|];; |
let a = [|4.1; 7.2; 1.7; 9.3; 4.4; 3.2|];; |
||
median a;;</ |
median a;;</syntaxhighlight> |
||
=={{header|Octave}}== |
=={{header|Octave}}== |
||
Of course Octave has its own <tt>median</tt> function we can use to check our implementation. The Octave's median function, however, does not handle the case you pass in a void vector. |
Of course Octave has its own <tt>median</tt> function we can use to check our implementation. The Octave's median function, however, does not handle the case you pass in a void vector. |
||
< |
<syntaxhighlight lang="octave">function y = median2(v) |
||
if (numel(v) < 1) |
if (numel(v) < 1) |
||
y = NA; |
y = NA; |
||
Line 226: | Line 4,350: | ||
disp(median(a)) |
disp(median(a)) |
||
disp(median2(b)) % 4.25 |
disp(median2(b)) % 4.25 |
||
disp(median(b))</ |
disp(median(b))</syntaxhighlight> |
||
=={{header|ooRexx}}== |
|||
<syntaxhighlight lang="oorexx"> |
|||
call testMedian .array~of(10, 9, 8, 7, 6, 5, 4, 3, 2, 1) |
|||
call testMedian .array~of(10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, .11) |
|||
call testMedian .array~of(10, 20, 30, 40, 50, -100, 4.7, -11e2) |
|||
call testMedian .array~new |
|||
::routine testMedian |
|||
use arg numbers |
|||
say "numbers =" numbers~toString("l", ", ") |
|||
say "median =" median(numbers) |
|||
say |
|||
::routine median |
|||
use arg numbers |
|||
if numbers~isempty then return 0 |
|||
-- make a copy so the sort does not alter the |
|||
-- original set. This also means this will |
|||
-- work with lists and queues as well |
|||
numbers = numbers~makearray |
|||
-- sort and return the middle element |
|||
numbers~sortWith(.numbercomparator~new) |
|||
size = numbers~items |
|||
-- this handles the odd value too |
|||
return numbers[size%2 + size//2] |
|||
-- a custom comparator that sorts strings as numeric values rather than |
|||
-- strings |
|||
::class numberComparator subclass comparator |
|||
::method compare |
|||
use strict arg left, right |
|||
-- perform the comparison on the names. By subtracting |
|||
-- the two and returning the sign, we give the expected |
|||
-- results for the compares |
|||
return (left - right)~sign |
|||
</syntaxhighlight> |
|||
=={{header|Oz}}== |
|||
<syntaxhighlight lang="oz">declare |
|||
fun {Median Xs} |
|||
Len = {Length Xs} |
|||
Mid = Len div 2 + 1 %% 1-based index |
|||
Sorted = {Sort Xs Value.'<'} |
|||
in |
|||
if {IsOdd Len} then {Nth Sorted Mid} |
|||
else ({Nth Sorted Mid} + {Nth Sorted Mid-1}) / 2.0 |
|||
end |
|||
end |
|||
in |
|||
{Show {Median [4.1 5.6 7.2 1.7 9.3 4.4 3.2]}} |
|||
{Show {Median [4.1 7.2 1.7 9.3 4.4 3.2]}}</syntaxhighlight> |
|||
=={{header|PARI/GP}}== |
|||
Sorting solution. |
|||
<syntaxhighlight lang="parigp">median(v)={ |
|||
vecsort(v)[#v\2] |
|||
};</syntaxhighlight> |
|||
Linear-time solution, mostly proof-of-concept but perhaps suitable for large lists. |
|||
<syntaxhighlight lang="parigp">BFPRT(v,k=#v\2)={ |
|||
if(#v<15, return(vecsort(v)[k])); |
|||
my(u=List(),pivot,left=List(),right=List()); |
|||
forstep(i=1,#v-4,5, |
|||
listput(u,BFPRT([v[i],v[i+1],v[i+2],v[i+3],v[i+4]])) |
|||
); |
|||
pivot=BFPRT(Vec(u)); |
|||
u=0; |
|||
for(i=1,#v, |
|||
if(v[i]<pivot, |
|||
listput(left,v[i]) |
|||
, |
|||
listput(right,v[i]) |
|||
) |
|||
); |
|||
if(k>#left, |
|||
BFPRT(right, k-#left) |
|||
, |
|||
BFPRT(left, k) |
|||
) |
|||
};</syntaxhighlight> |
|||
=={{header|Pascal}}== |
|||
{{works with|Free_Pascal}} |
|||
<syntaxhighlight lang="pascal">Program AveragesMedian(output); |
|||
type |
|||
TDoubleArray = array of double; |
|||
procedure bubbleSort(var list: TDoubleArray); |
|||
var |
|||
i, j, n: integer; |
|||
t: double; |
|||
begin |
|||
n := length(list); |
|||
for i := n downto 2 do |
|||
for j := 0 to i - 1 do |
|||
if list[j] > list[j + 1] then |
|||
begin |
|||
t := list[j]; |
|||
list[j] := list[j + 1]; |
|||
list[j + 1] := t; |
|||
end; |
|||
end; |
|||
function Median(aArray: TDoubleArray): double; |
|||
var |
|||
lMiddleIndex: integer; |
|||
begin |
|||
bubbleSort(aArray); |
|||
lMiddleIndex := (high(aArray) - low(aArray)) div 2; |
|||
if Odd(Length(aArray)) then |
|||
Median := aArray[lMiddleIndex + 1] |
|||
else |
|||
Median := (aArray[lMiddleIndex + 1] + aArray[lMiddleIndex]) / 2; |
|||
end; |
|||
var |
|||
A: TDoubleArray; |
|||
i: integer; |
|||
begin |
|||
randomize; |
|||
setlength(A, 7); |
|||
for i := low(A) to high(A) do |
|||
begin |
|||
A[i] := 100 * random; |
|||
write (A[i]:7:3, ' '); |
|||
end; |
|||
writeln; |
|||
writeln('Median: ', Median(A):7:3); |
|||
setlength(A, 6); |
|||
for i := low(A) to high(A) do |
|||
begin |
|||
A[i] := 100 * random; |
|||
write (A[i]:7:3, ' '); |
|||
end; |
|||
writeln; |
|||
writeln('Median: ', Median(A):7:3); |
|||
end.</syntaxhighlight> |
|||
Output: |
|||
<pre>% ./Median |
|||
28.207 74.916 51.695 72.486 51.118 3.241 73.807 |
|||
Median: 51.695 |
|||
27.984 89.172 0.250 66.316 41.805 60.043 |
|||
Median: 50.924 |
|||
</pre> |
|||
=={{header|Perl}}== |
|||
{{trans|Python}} |
|||
<syntaxhighlight lang="perl">sub median { |
|||
my @a = sort {$a <=> $b} @_; |
|||
return ($a[$#a/2] + $a[@a/2]) / 2; |
|||
}</syntaxhighlight> |
|||
=={{header|Phix}}== |
|||
The obvious simple way: |
|||
<!--<syntaxhighlight lang="phix">(phixonline)--> |
|||
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span> |
|||
<span style="color: #008080;">function</span> <span style="color: #000000;">median</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #004080;">atom</span> <span style="color: #000000;">res</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> |
|||
<span style="color: #004080;">integer</span> <span style="color: #000000;">l</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">),</span> <span style="color: #000000;">k</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">((</span><span style="color: #000000;">l</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #000000;">l</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #000000;">s</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sort</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">k</span><span style="color: #0000FF;">]</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #7060A8;">remainder</span><span style="color: #0000FF;">(</span><span style="color: #000000;">l</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">res</span><span style="color: #0000FF;">+</span><span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">k</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">])/</span><span style="color: #000000;">2</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #008080;">return</span> <span style="color: #000000;">res</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span> |
|||
<!--</syntaxhighlight>--> |
|||
It is also possible to use the [[Quickselect_algorithm#Phix|quick_select]] routine for a small (20%) performance improvement, |
|||
which as suggested below may with luck be magnified by retaining any partially sorted results. |
|||
<!--<syntaxhighlight lang="phix">(phixonline)--> |
|||
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span> |
|||
<span style="color: #008080;">function</span> <span style="color: #000000;">medianq</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #004080;">atom</span> <span style="color: #000000;">res</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">tmp</span> |
|||
<span style="color: #004080;">integer</span> <span style="color: #000000;">l</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">),</span> <span style="color: #000000;">k</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">((</span><span style="color: #000000;">l</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #000000;">l</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #0000FF;">{</span><span style="color: #000000;">s</span><span style="color: #0000FF;">,</span><span style="color: #000000;">res</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">quick_select</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">,</span><span style="color: #000000;">k</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #7060A8;">remainder</span><span style="color: #0000FF;">(</span><span style="color: #000000;">l</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #0000FF;">{</span><span style="color: #000000;">s</span><span style="color: #0000FF;">,</span><span style="color: #000000;">tmp</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">quick_select</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">,</span><span style="color: #000000;">k</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">res</span><span style="color: #0000FF;">+</span><span style="color: #000000;">tmp</span><span style="color: #0000FF;">)/</span><span style="color: #000000;">2</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #008080;">return</span> <span style="color: #000000;">res</span> <span style="color: #000080;font-style:italic;">-- (or perhaps return {s,res})</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span> |
|||
<!--</syntaxhighlight>--> |
|||
=={{header|Phixmonti}}== |
|||
<syntaxhighlight lang="phixmonti">include ..\Utilitys.pmt |
|||
def median /# l -- n #/ |
|||
sort len 2 / >ps |
|||
tps .5 + int 2 slice nip |
|||
ps> dup int != if |
|||
1 get nip |
|||
else |
|||
sum 2 / |
|||
endif |
|||
enddef |
|||
( 4.1 5.6 7.2 1.7 9.3 4.4 3.2 ) median ? |
|||
( 4.1 7.2 1.7 9.3 4.4 3.2 ) median ?</syntaxhighlight> |
|||
=={{header|PHP}}== |
|||
This solution uses the sorting method of finding the median. |
|||
<syntaxhighlight lang="php"> |
|||
function median($arr) |
|||
{ |
|||
sort($arr); |
|||
$count = count($arr); //count the number of values in array |
|||
$middleval = floor(($count-1)/2); // find the middle value, or the lowest middle value |
|||
if ($count % 2) { // odd number, middle is the median |
|||
$median = $arr[$middleval]; |
|||
} else { // even number, calculate avg of 2 medians |
|||
$low = $arr[$middleval]; |
|||
$high = $arr[$middleval+1]; |
|||
$median = (($low+$high)/2); |
|||
} |
|||
return $median; |
|||
} |
|||
echo median(array(4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2)) . "\n"; // 4.4 |
|||
echo median(array(4.1, 7.2, 1.7, 9.3, 4.4, 3.2)) . "\n"; // 4.25 |
|||
</syntaxhighlight> |
|||
=={{header|Picat}}== |
|||
<syntaxhighlight lang="picat">go => |
|||
Lists = [ |
|||
[1.121,10.3223,3.41,12.1,0.01], |
|||
1..10, |
|||
1..11, |
|||
[3], |
|||
[3,4], |
|||
[], |
|||
[4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2], |
|||
[4.1, 7.2, 1.7, 9.3, 4.4, 3.2], |
|||
[5.1, 2.6, 6.2, 8.8, 4.6, 4.1], |
|||
[5.1, 2.6, 8.8, 4.6, 4.1]], |
|||
foreach(List in Lists) |
|||
println([List, median=median(List)]) |
|||
end, |
|||
nl. |
|||
median([]) = undef. |
|||
median([X]) = X. |
|||
median(L) = cond(Len mod 2 == 1, LL[H+1], avg([LL[H],LL[H+1]])) => |
|||
Len = L.length, |
|||
H = Len // 2, |
|||
LL = sort(L).</syntaxhighlight> |
|||
{{out}} |
|||
<pre>[[1.121,10.3223,3.41,12.1,0.01],median = 3.41] |
|||
[[1,2,3,4,5,6,7,8,9,10],median = 5.5] |
|||
[[1,2,3,4,5,6,7,8,9,10,11],median = 6] |
|||
[[3],median = 3] |
|||
[[3,4],median = 3.5] |
|||
[[],median = undef] |
|||
[[4.1,5.6,7.2,1.7,9.300000000000001,4.4,3.2],median = 4.4] |
|||
[[4.1,7.2,1.7,9.300000000000001,4.4,3.2],median = 4.25] |
|||
[[5.1,2.6,6.2,8.800000000000001,4.6,4.1],median = 4.85] |
|||
[[5.1,2.6,8.800000000000001,4.6,4.1],median = 4.6]</pre> |
|||
=={{header|PicoLisp}}== |
|||
<syntaxhighlight lang="picolisp">(de median (Lst) |
|||
(let N (length Lst) |
|||
(if (bit? 1 N) |
|||
(get (sort Lst) (/ (inc N) 2)) |
|||
(setq Lst (nth (sort Lst) (/ N 2))) |
|||
(/ (+ (car Lst) (cadr Lst)) 2) ) ) ) |
|||
(scl 2) |
|||
(prinl (round (median (1.0 2.0 3.0)))) |
|||
(prinl (round (median (1.0 2.0 3.0 4.0)))) |
|||
(prinl (round (median (5.1 2.6 6.2 8.8 4.6 4.1)))) |
|||
(prinl (round (median (5.1 2.6 8.8 4.6 4.1))))</syntaxhighlight> |
|||
Output: |
|||
<pre>2.00 |
|||
2.50 |
|||
4.85 |
|||
4.60</pre> |
|||
=={{header|PL/I}}== |
|||
<syntaxhighlight lang="pli">call sort(A); |
|||
n = dimension(A,1); |
|||
if iand(n,1) = 1 then /* an odd number of elements */ |
|||
median = A(n/2); |
|||
else /* an even number of elements */ |
|||
median = (a(n/2) + a(trunc(n/2)+1) )/2;</syntaxhighlight> |
|||
=={{header|PowerShell}}== |
|||
This function returns an object containing the minimal amount of statistical data, including Median, and could be modified to take input directly from the pipeline. |
|||
All statistical properties could easily be added to the output object. |
|||
<syntaxhighlight lang="powershell"> |
|||
function Measure-Data |
|||
{ |
|||
[CmdletBinding()] |
|||
[OutputType([PSCustomObject])] |
|||
Param |
|||
( |
|||
[Parameter(Mandatory=$true, |
|||
Position=0)] |
|||
[double[]] |
|||
$Data |
|||
) |
|||
Begin |
|||
{ |
|||
function Get-Mode ([double[]]$Data) |
|||
{ |
|||
if ($Data.Count -gt ($Data | Select-Object -Unique).Count) |
|||
{ |
|||
$groups = $Data | Group-Object | Sort-Object -Property Count -Descending |
|||
return ($groups | Where-Object {[double]$_.Count -eq [double]$groups[0].Count}).Name | ForEach-Object {[double]$_} |
|||
} |
|||
else |
|||
{ |
|||
return $null |
|||
} |
|||
} |
|||
function Get-StandardDeviation ([double[]]$Data) |
|||
{ |
|||
$variance = 0 |
|||
$average = $Data | Measure-Object -Average | Select-Object -Property Count, Average |
|||
foreach ($number in $Data) |
|||
{ |
|||
$variance += [Math]::Pow(($number - $average.Average),2) |
|||
} |
|||
return [Math]::Sqrt($variance / ($average.Count-1)) |
|||
} |
|||
function Get-Median ([double[]]$Data) |
|||
{ |
|||
if ($Data.Count % 2) |
|||
{ |
|||
return $Data[[Math]::Floor($Data.Count/2)] |
|||
} |
|||
else |
|||
{ |
|||
return ($Data[$Data.Count/2], $Data[$Data.Count/2-1] | Measure-Object -Average).Average |
|||
} |
|||
} |
|||
} |
|||
Process |
|||
{ |
|||
$Data = $Data | Sort-Object |
|||
$Data | Measure-Object -Maximum -Minimum -Sum -Average | |
|||
Select-Object -Property Count, |
|||
Sum, |
|||
Minimum, |
|||
Maximum, |
|||
@{Name='Range'; Expression={$_.Maximum - $_.Minimum}}, |
|||
@{Name='Mean' ; Expression={$_.Average}} | |
|||
Add-Member -MemberType NoteProperty -Name Median -Value (Get-Median $Data) -PassThru | |
|||
Add-Member -MemberType NoteProperty -Name StandardDeviation -Value (Get-StandardDeviation $Data) -PassThru | |
|||
Add-Member -MemberType NoteProperty -Name Mode -Value (Get-Mode $Data) -PassThru |
|||
} |
|||
} |
|||
</syntaxhighlight> |
|||
<syntaxhighlight lang="powershell"> |
|||
$statistics = Measure-Data 4, 5, 6, 7, 7, 7, 8, 1, 1, 1, 2, 3 |
|||
$statistics |
|||
</syntaxhighlight> |
|||
{{Out}} |
|||
<pre> |
|||
Count : 12 |
|||
Sum : 52 |
|||
Minimum : 1 |
|||
Maximum : 8 |
|||
Range : 7 |
|||
Mean : 4.33333333333333 |
|||
Median : 4.5 |
|||
StandardDeviation : 2.67423169368609 |
|||
Mode : {1, 7} |
|||
</pre> |
|||
Median only: |
|||
<syntaxhighlight lang="powershell"> |
|||
$statistics.Median |
|||
</syntaxhighlight> |
|||
{{Out}} |
|||
<pre> |
|||
4.5 |
|||
</pre> |
|||
=={{header|Processing}}== |
|||
<syntaxhighlight lang="processing">void setup() { |
|||
float[] numbers = {3.1, 4.1, 5.9, 2.6, 5.3, 5.8}; |
|||
println(median(numbers)); |
|||
numbers = shorten(numbers); |
|||
println(median(numbers)); |
|||
} |
|||
float median(float[] nums) { |
|||
nums = sort(nums); |
|||
float median = (nums[(nums.length - 1) / 2] + nums[nums.length / 2]) / 2.0; |
|||
return median; |
|||
}</syntaxhighlight> |
|||
{{Out}} |
|||
<pre>4.7 |
|||
4.1</pre> |
|||
=={{header|Prolog}}== |
|||
<syntaxhighlight lang="prolog">median(L, Z) :- |
|||
length(L, Length), |
|||
I is Length div 2, |
|||
Rem is Length rem 2, |
|||
msort(L, S), |
|||
maplist(sumlist, [[I, Rem], [I, 1]], Mid), |
|||
maplist(nth1, Mid, [S, S], X), |
|||
sumlist(X, Y), |
|||
Z is Y/2.</syntaxhighlight> |
|||
=={{header|Pure}}== |
|||
Inspired by the Haskell version. |
|||
<syntaxhighlight lang="pure">median x = (/(2-rem)) $ foldl1 (+) $ take (2-rem) $ drop (mid-(1-rem)) $ sort (<=) x |
|||
when len = # x; |
|||
mid = len div 2; |
|||
rem = len mod 2; |
|||
end;</syntaxhighlight> |
|||
Output:<pre>> median [1, 3, 5]; |
|||
3.0 |
|||
> median [1, 2, 3, 4]; |
|||
2.5 |
|||
</pre> |
|||
=={{header|PureBasic}}== |
|||
<syntaxhighlight lang="purebasic">Procedure.d median(Array values.d(1), length.i) |
|||
If length = 0 : ProcedureReturn 0.0 : EndIf |
|||
SortArray(values(), #PB_Sort_Ascending) |
|||
If length % 2 |
|||
ProcedureReturn values(length / 2) |
|||
EndIf |
|||
ProcedureReturn 0.5 * (values(length / 2 - 1) + values(length / 2)) |
|||
EndProcedure |
|||
Procedure.i readArray(Array values.d(1)) |
|||
Protected length.i, i.i |
|||
Read.i length |
|||
ReDim values(length - 1) |
|||
For i = 0 To length - 1 |
|||
Read.d values(i) |
|||
Next |
|||
ProcedureReturn i |
|||
EndProcedure |
|||
Dim floats.d(0) |
|||
Restore array1 |
|||
length.i = readArray(floats()) |
|||
Debug median(floats(), length) |
|||
Restore array2 |
|||
length.i = readArray(floats()) |
|||
Debug median(floats(), length) |
|||
DataSection |
|||
array1: |
|||
Data.i 7 |
|||
Data.d 4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2 |
|||
array2: |
|||
Data.i 6 |
|||
Data.d 4.1, 7.2, 1.7, 9.3, 4.4, 3.2 |
|||
EndDataSection</syntaxhighlight> |
|||
=={{header|Python}}== |
=={{header|Python}}== |
||
< |
<syntaxhighlight lang="python">def median(aray): |
||
srtd = sorted(aray) |
srtd = sorted(aray) |
||
alen = len(srtd) |
alen = len(srtd) |
||
Line 237: | Line 4,837: | ||
print a, median(a) |
print a, median(a) |
||
a = (4.1, 7.2, 1.7, 9.3, 4.4, 3.2) |
a = (4.1, 7.2, 1.7, 9.3, 4.4, 3.2) |
||
print a, median(a)</ |
print a, median(a)</syntaxhighlight> |
||
=={{header|R}}== |
|||
R has its built-in median function. |
|||
{{trans|Octave}} |
|||
<syntaxhighlight lang="rsplus">omedian <- function(v) { |
|||
if ( length(v) < 1 ) |
|||
NA |
|||
else { |
|||
sv <- sort(v) |
|||
l <- length(sv) |
|||
if ( l %% 2 == 0 ) |
|||
(sv[floor(l/2)+1] + sv[floor(l/2)])/2 |
|||
else |
|||
sv[floor(l/2)+1] |
|||
} |
|||
} |
|||
a <- c(4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2) |
|||
b <- c(4.1, 7.2, 1.7, 9.3, 4.4, 3.2) |
|||
print(median(a)) # 4.4 |
|||
print(omedian(a)) |
|||
print(median(b)) # 4.25 |
|||
print(omedian(b))</syntaxhighlight> |
|||
=={{header|Racket}}== |
|||
<syntaxhighlight lang="racket">#lang racket |
|||
(define (median numbers) |
|||
(define sorted (list->vector (sort (vector->list numbers) <))) |
|||
(define count (vector-length numbers)) |
|||
(if (zero? count) |
|||
#f |
|||
(/ (+ (vector-ref sorted (floor (/ (sub1 count) 2))) |
|||
(vector-ref sorted (floor (/ count 2)))) |
|||
2))) |
|||
(median '#(5 3 4)) ;; 4 |
|||
(median '#()) ;; #f |
|||
(median '#(5 4 2 3)) ;; 7/2 |
|||
(median '#(3 4 1 -8.4 7.2 4 1 1.2)) ;; 2.1</syntaxhighlight> |
|||
=={{header|Raku}}== |
|||
(formerly Perl 6) |
|||
{{works with|Rakudo|2016.08}} |
|||
<syntaxhighlight lang="raku" line>sub median { |
|||
my @a = sort @_; |
|||
return (@a[(*-1) div 2] + @a[* div 2]) / 2; |
|||
}</syntaxhighlight> |
|||
Notes: |
|||
* The <tt>div</tt> operator does integer division. The <tt>/</tt> operator (rational number division) would work too, since the array subscript automatically coerces to <tt>Int</tt>, but using <tt>div</tt> is more explicit (i.e. clearer to readers) as well as faster, and thus recommended in cases like this. |
|||
* The <tt>*</tt> inside the subscript stands for the array's length ([https://raku.org/language/subscripts.html#From_the_end see documentation]). |
|||
<br> |
|||
In a slightly more compact way: |
|||
<syntaxhighlight lang="raku" line>sub median { @_.sort[(*-1)/2, */2].sum / 2 }</syntaxhighlight> |
|||
=={{header|REBOL}}== |
|||
<syntaxhighlight lang="rebol"> |
|||
median: func [ |
|||
"Returns the midpoint value in a series of numbers; half the values are above, half are below." |
|||
block [any-block!] |
|||
/local len mid |
|||
][ |
|||
if empty? block [return none] |
|||
block: sort copy block |
|||
len: length? block |
|||
mid: to integer! len / 2 |
|||
either odd? len [ |
|||
pick block add 1 mid |
|||
][ |
|||
(block/:mid) + (pick block add 1 mid) / 2 |
|||
] |
|||
] |
|||
</syntaxhighlight> |
|||
=={{header|ReScript}}== |
|||
<syntaxhighlight lang="rescript">let median = (arr) => |
|||
{ |
|||
let float_compare = (a, b) => { |
|||
let diff = a -. b |
|||
if diff == 0.0 { 0 } else |
|||
if diff > 0.0 { 1 } else { -1 } |
|||
} |
|||
let _ = Js.Array2.sortInPlaceWith(arr, float_compare) |
|||
let count = Js.Array.length(arr) |
|||
// find the middle value, or the lowest middle value |
|||
let middleval = ((count - 1) / 2) |
|||
let median = |
|||
if (mod(count, 2) != 0) { // odd number, middle is the median |
|||
arr[middleval] |
|||
} else { // even number, calculate avg of 2 medians |
|||
let low = arr[middleval] |
|||
let high = arr[middleval+1] |
|||
((low +. high) /. 2.0) |
|||
} |
|||
median |
|||
} |
|||
Js.log(median([4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2])) |
|||
Js.log(median([4.1, 7.2, 1.7, 9.3, 4.4, 3.2]))</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
$ bsc median.res > median.bs.js |
|||
$ node median.bs.js |
|||
4.4 |
|||
4.25 |
|||
</pre> |
|||
=={{header|REXX}}== |
|||
<syntaxhighlight lang="rexx">/*REXX program finds the median of a vector (and displays the vector and median).*/ |
|||
/* ══════════vector════════════ ══show vector═══ ════════show result═══════════ */ |
|||
v= 1 9 2 4 ; say "vector" v; say 'median──────►' median(v); say |
|||
v= 3 1 4 1 5 9 7 6 ; say "vector" v; say 'median──────►' median(v); say |
|||
v= '3 4 1 -8.4 7.2 4 1 1.2'; say "vector" v; say 'median──────►' median(v); say |
|||
v= -1.2345678e99 2.3e700 ; say "vector" v; say 'median──────►' median(v); say |
|||
exit /*stick a fork in it, we're all done. */ |
|||
/*──────────────────────────────────────────────────────────────────────────────────────*/ |
|||
eSORT: procedure expose @. #; parse arg $; #= words($) /*$: is the vector. */ |
|||
do g=1 for #; @.g= word($, g); end /*g*/ /*convert list──►array*/ |
|||
h=# /*#: number elements.*/ |
|||
do while h>1; h= h % 2 /*cut entries by half.*/ |
|||
do i=1 for #-h; j= i; k= h + i /*sort lower section. */ |
|||
do while @.k<@.j; parse value @.j @.k with @.k @.j /*swap.*/ |
|||
if h>=j then leave; j= j - h; k= k - h /*diminish J and K.*/ |
|||
end /*while @.k<@.j*/ |
|||
end /*i*/ |
|||
end /*while h>1*/ /*end of exchange sort*/ |
|||
return |
|||
/*──────────────────────────────────────────────────────────────────────────────────────*/ |
|||
median: procedure; call eSORT arg(1); m= # % 2 /* % is REXX's integer division.*/ |
|||
n= m + 1 /*N: the next element after M. */ |
|||
if # // 2 then return @.n /*[odd?] // ◄───REXX's ÷ remainder*/ |
|||
return (@.m + @.n) / 2 /*process an even─element vector. */</syntaxhighlight> |
|||
{{out|output}} |
|||
<pre> |
|||
vector: 1 9 2 4 |
|||
median──────► 3 |
|||
vector: 3 1 4 1 5 9 7 6 |
|||
median──────► 4.5 |
|||
vector: 3 4 1 -8.4 7.2 4 1 1.2 |
|||
median──────► 2.1 |
|||
vector: -1.2345678e99 2.3e700 |
|||
median──────► 1.15000000E+700 |
|||
</pre> |
|||
=={{header|Ring}}== |
|||
<syntaxhighlight lang="ring"> |
|||
aList = [5,4,2,3] |
|||
see "medium : " + median(aList) + nl |
|||
func median aray |
|||
srtd = sort(aray) |
|||
alen = len(srtd) |
|||
if alen % 2 = 0 |
|||
return (srtd[alen/2] + srtd[alen/2 + 1]) / 2.0 |
|||
else return srtd[ceil(alen/2)] ok |
|||
</syntaxhighlight> |
|||
=={{header|RPL}}== |
|||
≪ '''SORT''' |
|||
DUP SIZE 1 + 2 / |
|||
DUP2 FLOOR GET ROT ROT CEIL GET + 2 / |
|||
≫ ''''MDIAN'''' STO |
|||
<code>SORT</code> became a standard RPL instruction in 1993, with the introduction of the HP-48G. For earlier RPL versions, users have to call the sorting program demonstrated [[Sorting algorithms/Bubble sort#RPL|here]]. |
|||
=={{header|Ruby}}== |
=={{header|Ruby}}== |
||
< |
<syntaxhighlight lang="ruby">def median(ary) |
||
return nil if ary.empty? |
return nil if ary.empty? |
||
mid, rem = ary.length.divmod(2) |
mid, rem = ary.length.divmod(2) |
||
Line 253: | Line 5,024: | ||
p median([5,3,4]) # => 4 |
p median([5,3,4]) # => 4 |
||
p median([5,4,2,3]) # => 3.5 |
p median([5,4,2,3]) # => 3.5 |
||
p median([3,4,1,-8.4,7.2,4,1,1.2]) # => 2.1</ |
p median([3,4,1,-8.4,7.2,4,1,1.2]) # => 2.1</syntaxhighlight> |
||
Alternately: |
|||
<syntaxhighlight lang="ruby">def median(aray) |
|||
srtd = aray.sort |
|||
alen = srtd.length |
|||
(srtd[(alen-1)/2] + srtd[alen/2]) / 2.0 |
|||
end</syntaxhighlight> |
|||
=={{header|Run BASIC}}== |
|||
<syntaxhighlight lang="runbasic">sqliteconnect #mem, ":memory:" |
|||
mem$ = "CREATE TABLE med (x float)" |
|||
#mem execute(mem$) |
|||
a$ ="4.1,5.6,7.2,1.7,9.3,4.4,3.2" :gosub [median] |
|||
a$ ="4.1,7.2,1.7,9.3,4.4,3.2" :gosub [median] |
|||
a$ ="4.1,4,1.2,6.235,7868.33" :gosub [median] |
|||
a$ ="1,5,3,2,4" :gosub [median] |
|||
a$ ="1,5,3,6,4,2" :gosub [median] |
|||
a$ ="4.4,2.3,-1.7,7.5,6.6,0.0,1.9,8.2,9.3,4.5" :gosub [median]' |
|||
end |
|||
[median] |
|||
#mem execute("DELETE FROM med") |
|||
for i = 1 to 100 |
|||
v$ = word$( a$, i, ",") |
|||
if v$ = "" then exit for |
|||
mem$ = "INSERT INTO med values(";v$;")" |
|||
#mem execute(mem$) |
|||
next i |
|||
mem$ = "SELECT AVG(x) as median FROM (SELECT x FROM med |
|||
ORDER BY x LIMIT 2 - (SELECT COUNT(*) FROM med) % 2 |
|||
OFFSET (SELECT (COUNT(*) - 1) / 2 |
|||
FROM med))" |
|||
#mem execute(mem$) |
|||
#row = #mem #nextrow() |
|||
median = #row median() |
|||
print " Median :";median;chr$(9);" Values:";a$ |
|||
RETURN</syntaxhighlight>Output: |
|||
<pre>Median :4.4 Values:4.1,5.6,7.2,1.7,9.3,4.4,3.2 |
|||
Median :4.25 Values:4.1,7.2,1.7,9.3,4.4,3.2 |
|||
Median :4.1 Values:4.1,4,1.2,6.235,7868.33 |
|||
Median :3.0 Values:1,5,3,2,4 |
|||
Median :3.5 Values:1,5,3,6,4,2 |
|||
Median :4.45 Values:4.4,2.3,-1.7,7.5,6.6,0.0,1.9,8.2,9.3,4.5</pre> |
|||
=={{header|Rust}}== |
|||
Sorting, then obtaining the median element: |
|||
<syntaxhighlight lang="rust">fn median(mut xs: Vec<f64>) -> f64 { |
|||
// sort in ascending order, panic on f64::NaN |
|||
xs.sort_by(|x,y| x.partial_cmp(y).unwrap() ); |
|||
let n = xs.len(); |
|||
if n % 2 == 0 { |
|||
(xs[n/2] + xs[n/2 - 1]) / 2.0 |
|||
} else { |
|||
xs[n/2] |
|||
} |
|||
} |
|||
fn main() { |
|||
let nums = vec![2.,3.,5.,0.,9.,82.,353.,32.,12.]; |
|||
println!("{:?}", median(nums)) |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre>9</pre> |
|||
=={{header|Scala}}== |
|||
{{works with|Scala|2.8}} (See the Scala discussion on [[Mean]] for more information.) |
|||
<syntaxhighlight lang="scala">def median[T](s: Seq[T])(implicit n: Fractional[T]) = { |
|||
import n._ |
|||
val (lower, upper) = s.sortWith(_<_).splitAt(s.size / 2) |
|||
if (s.size % 2 == 0) (lower.last + upper.head) / fromInt(2) else upper.head |
|||
}</syntaxhighlight> |
|||
This isn't really optimal. The methods <tt>splitAt</tt> and <tt>last</tt> are O(n/2) |
|||
on many sequences, and then there's the lower bound imposed by the sort. Finally, |
|||
we call <tt>size</tt> two times, and it can be O(n). |
|||
=={{header|Scheme}}== |
|||
{{trans|Python}} |
|||
Using Rosetta Code's [[Bubble_Sort#Scheme|bubble-sort function]] |
|||
<syntaxhighlight lang="scheme">(define (median l) |
|||
(* (+ (list-ref (bubble-sort l >) (round (/ (- (length l) 1) 2))) |
|||
(list-ref (bubble-sort l >) (round (/ (length l) 2)))) 0.5))</syntaxhighlight> |
|||
Using [http://srfi.schemers.org/srfi-95/srfi-95.html SRFI-95]: |
|||
<syntaxhighlight lang="scheme">(define (median l) |
|||
(* (+ (list-ref (sort l less?) (round (/ (- (length l) 1) 2))) |
|||
(list-ref (sort l less?) (round (/ (length l) 2)))) 0.5))</syntaxhighlight> |
|||
=={{header|Seed7}}== |
|||
<syntaxhighlight lang="seed7">$ include "seed7_05.s7i"; |
|||
include "float.s7i"; |
|||
const type: floatList is array float; |
|||
const func float: median (in floatList: floats) is func |
|||
result |
|||
var float: median is 0.0; |
|||
local |
|||
var floatList: sortedFloats is 0 times 0.0; |
|||
begin |
|||
sortedFloats := sort(floats); |
|||
if odd(length(sortedFloats)) then |
|||
median := sortedFloats[succ(length(sortedFloats)) div 2]; |
|||
else |
|||
median := 0.5 * (sortedFloats[length(sortedFloats) div 2] + |
|||
sortedFloats[succ(length(sortedFloats) div 2)]); |
|||
end if; |
|||
end func; |
|||
const proc: main is func |
|||
local |
|||
const floatList: flist1 is [] (5.1, 2.6, 6.2, 8.8, 4.6, 4.1); |
|||
const floatList: flist2 is [] (5.1, 2.6, 8.8, 4.6, 4.1); |
|||
begin |
|||
writeln("flist1 median is " <& median(flist1) digits 2 lpad 7); # 4.85 |
|||
writeln("flist2 median is " <& median(flist2) digits 2 lpad 7); # 4.60 |
|||
end func;</syntaxhighlight> |
|||
=={{header|SenseTalk}}== |
|||
SenseTalk has a built-in median function. This example also shows the implementation of a customMedian function that returns the same results. |
|||
<syntaxhighlight lang="sensetalk">put the median of [4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2] |
|||
put the median of [4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2, 6.6] |
|||
put customMedian of [4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2] |
|||
put customMedian of [4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2, 6.6] |
|||
to handle customMedian of list |
|||
sort list |
|||
if the number of items in list is an even number then |
|||
set lowMid to the number of items in list divided by 2 |
|||
return (item lowMid of list + item lowMid+1 of list) / 2 |
|||
else |
|||
return the middle item of list |
|||
end if |
|||
end customMedian</syntaxhighlight> |
|||
Output: |
|||
<syntaxhighlight lang="sensetalk">4.4 |
|||
5 |
|||
4.4 |
|||
5</syntaxhighlight> |
|||
=={{header|Sidef}}== |
|||
<syntaxhighlight lang="ruby">func median(arry) { |
|||
var srtd = arry.sort; |
|||
var alen = srtd.length; |
|||
srtd[(alen-1)/2]+srtd[alen/2] / 2; |
|||
}</syntaxhighlight> |
|||
=={{header|Slate}}== |
|||
<syntaxhighlight lang="slate">s@(Sequence traits) median |
|||
[ |
|||
s isEmpty |
|||
ifTrue: [Nil] |
|||
ifFalse: |
|||
[| sorted | |
|||
sorted: s sort. |
|||
sorted length `cache isEven |
|||
ifTrue: [(sorted middle + (sorted at: sorted indexMiddle - 1)) / 2] |
|||
ifFalse: [sorted middle]] |
|||
].</syntaxhighlight> |
|||
<syntaxhighlight lang="slate">inform: { 4.1 . 5.6 . 7.2 . 1.7 . 9.3 . 4.4 . 3.2 } median. |
|||
inform: { 4.1 . 7.2 . 1.7 . 9.3 . 4.4 . 3.2 } median.</syntaxhighlight> |
|||
=={{header|Smalltalk}}== |
=={{header|Smalltalk}}== |
||
{{works with|GNU Smalltalk}} |
{{works with|GNU Smalltalk}} |
||
< |
<syntaxhighlight lang="smalltalk">OrderedCollection extend [ |
||
median [ |
median [ |
||
self size = 0 |
self size = 0 |
||
Line 270: | Line 5,210: | ||
ifTrue: [ ^nil ] |
ifTrue: [ ^nil ] |
||
] |
] |
||
].</ |
].</syntaxhighlight> |
||
< |
<syntaxhighlight lang="smalltalk">{ 4.1 . 5.6 . 7.2 . 1.7 . 9.3 . 4.4 . 3.2 } asOrderedCollection |
||
median displayNl. |
median displayNl. |
||
{ 4.1 . 7.2 . 1.7 . 9.3 . 4.4 . 3.2 } asOrderedCollection |
{ 4.1 . 7.2 . 1.7 . 9.3 . 4.4 . 3.2 } asOrderedCollection |
||
median displayNl.</ |
median displayNl.</syntaxhighlight> |
||
=={{header|Stata}}== |
|||
Use '''[https://www.stata.com/help.cgi?summarize summarize]''' to compute the median of a variable (as well as other basic statistics). |
|||
<syntaxhighlight lang="stata">set obs 100000 |
|||
gen x=rbeta(0.2,1.3) |
|||
quietly summarize x, detail |
|||
display r(p50)</syntaxhighlight> |
|||
Here is a straightforward implementation using '''[https://www.stata.com/help.cgi? sort]'''. |
|||
<syntaxhighlight lang="stata">program calcmedian, rclass sortpreserve |
|||
sort `1' |
|||
if mod(_N,2)==0 { |
|||
return scalar p50=(`1'[_N/2]+`1'[_N/2+1])/2 |
|||
} |
|||
else { |
|||
return scalar p50=`1'[(_N-1)/2] |
|||
} |
|||
end |
|||
calcmedian x |
|||
display r(p50)</syntaxhighlight> |
|||
=={{header|Swift}}== |
|||
===A full implementation=== |
|||
<syntaxhighlight lang="swift"> |
|||
// Utility to aid easy type conversion |
|||
extension Double { |
|||
init(withNum v: any Numeric) { |
|||
switch v { |
|||
case let ii as any BinaryInteger: self.init(ii) |
|||
case let ff as any BinaryFloatingPoint: self.init(ff) |
|||
default: self.init() |
|||
} |
|||
} |
|||
} |
|||
extension Array where Element: Numeric & Comparable { |
|||
// Helper func for random element in range |
|||
func randomElement(within: Range<Int>) -> Element { |
|||
return self[.random(in: within)] |
|||
} |
|||
mutating func median() -> Double? { |
|||
switch self.count { |
|||
case 0: return nil |
|||
case 1: return Double(withNum: self[0]) |
|||
case 2: return self.reduce(0, {sum,this in sum + Double(withNum: this)/2.0}) |
|||
default: break |
|||
} |
|||
let pTarget: Int = self.count / 2 + 1 |
|||
let resultSetLen: Int = self.count.isMultiple(of: 2) ? 2 : 1 |
|||
func divideAndConquer(bottom: Int, top: Int, goal: Int) -> Int { |
|||
var (lower,upper) = (bottom,top) |
|||
while true { |
|||
let splitVal = self.randomElement(within: lower..<upper) |
|||
let partitionIndex = self.partition(subrange: lower..<upper, by: {$0 > splitVal}) |
|||
switch partitionIndex { |
|||
case goal: return partitionIndex |
|||
case ..<goal: lower = partitionIndex |
|||
default: upper = partitionIndex |
|||
} |
|||
} |
|||
} |
|||
// Split just above the 'median point' |
|||
var pIndex = divideAndConquer(bottom: 0, top: self.count, goal: pTarget) |
|||
// Shove the highest 'low' values into the result slice |
|||
pIndex = divideAndConquer(bottom: 0, top: pIndex, goal: pIndex - resultSetLen) |
|||
// Average the contents of the result slice |
|||
return self[pIndex..<pIndex + resultSetLen] |
|||
.reduce(0.0, {sum,this in sum + Double(withNum: this)/Double(withNum: resultSetLen)}) |
|||
} |
|||
} |
|||
</syntaxhighlight> |
|||
Usage: |
|||
<syntaxhighlight lang="swift"> |
|||
var c: [Double] = (0...100).map {_ in Double.random(in: 0...100)} |
|||
print(c.median()) |
|||
</syntaxhighlight> |
|||
=={{header|Tcl}}== |
=={{header|Tcl}}== |
||
< |
<syntaxhighlight lang="tcl">proc median args { |
||
set list [lsort -real $args] |
set list [lsort -real $args] |
||
set len [llength $list] |
set len [llength $list] |
||
Line 293: | Line 5,313: | ||
} |
} |
||
puts [median 3.0 4.0 1.0 -8.4 7.2 4.0 1.0 1.2]; # --> 2.1</ |
puts [median 3.0 4.0 1.0 -8.4 7.2 4.0 1.0 1.2]; # --> 2.1</syntaxhighlight> |
||
=={{header|TI-83 BASIC}}== |
|||
Using the built-in function: |
|||
<syntaxhighlight lang="ti83b">median({1.1, 2.5, 0.3241})</syntaxhighlight> |
|||
=={{header|TI-89 BASIC}}== |
|||
<syntaxhighlight lang="ti89b">median({3, 4, 1, -8.4, 7.2, 4, 1, 1})</syntaxhighlight> |
|||
=={{header|Ursala}}== |
|||
the simple way (sort first and then look in the middle) |
|||
<syntaxhighlight lang="ursala">#import std |
|||
#import flo |
|||
median = fleq-<; @K30K31X eql?\~&rh div\2.+ plus@lzPrhPX</syntaxhighlight> |
|||
test program, once with an odd length and once with an even length vector |
|||
<syntaxhighlight lang="ursala">#cast %eW |
|||
examples = |
|||
median~~ ( |
|||
<9.3,-2.0,4.0,7.3,8.1,4.1,-6.3,4.2,-1.0,-8.4>, |
|||
<8.3,-3.6,5.7,2.3,9.3,5.4,-2.3,6.3,9.9>)</syntaxhighlight> |
|||
output: |
|||
<pre> |
|||
(4.050000e+00,5.700000e+00)</pre> |
|||
=={{header|Vala}}== |
|||
Requires <code>--pkg posix -X -lm</code> compilation flags in order to use POSIX qsort, and to have access to math library. |
|||
<syntaxhighlight lang="vala">int compare_numbers(void* a_ref, void* b_ref) { |
|||
double a = *(double*) a_ref; |
|||
double b = *(double*) b_ref; |
|||
return a > b ? 1 : a < b ? -1 : 0; |
|||
} |
|||
double median(double[] elements) { |
|||
double[] clone = elements; |
|||
Posix.qsort(clone, clone.length, sizeof(double), compare_numbers); |
|||
double middle = clone.length / 2.0; |
|||
int first = (int) Math.floor(middle); |
|||
int second = (int) Math.ceil(middle); |
|||
return (clone[first] + clone[second]) / 2; |
|||
} |
|||
void main() { |
|||
double[] array1 = {2, 4, 6, 1, 7, 3, 5}; |
|||
double[] array2 = {2, 4, 6, 1, 7, 3, 5, 8}; |
|||
print(@"$(median(array1)) $(median(array2))\n"); |
|||
}</syntaxhighlight> |
|||
=={{header|VBA}}== |
|||
{{trans|Phix}} |
|||
Uses [[Quickselect_algorithm#VBA|quick select]]. |
|||
<syntaxhighlight lang="vb">Private Function medianq(s As Variant) As Double |
|||
Dim res As Double, tmp As Integer |
|||
Dim l As Integer, k As Integer |
|||
res = 0 |
|||
l = UBound(s): k = WorksheetFunction.Floor_Precise((l + 1) / 2, 1) |
|||
If l Then |
|||
res = quick_select(s, k) |
|||
If l Mod 2 = 0 Then |
|||
tmp = quick_select(s, k + 1) |
|||
res = (res + tmp) / 2 |
|||
End If |
|||
End If |
|||
medianq = res |
|||
End Function |
|||
Public Sub main2() |
|||
s = [{4, 2, 3, 5, 1, 6}] |
|||
Debug.Print medianq(s) |
|||
End Sub</syntaxhighlight>{{out}} |
|||
<pre> 3,5 </pre> |
|||
=={{header|Vedit macro language}}== |
|||
This is a simple implementation for positive integers using sorting. |
|||
The data is stored in current edit buffer in ascii representation. The values must be right justified. |
|||
The result is returned in text register @10. In case of even number of items, the lower middle value is returned. |
|||
<syntaxhighlight lang="vedit">Sort(0, File_Size, NOCOLLATE+NORESTORE) |
|||
EOF Goto_Line(Cur_Line/2) |
|||
Reg_Copy(10, 1)</syntaxhighlight> |
|||
=={{header|V (Vlang)}}== |
|||
<syntaxhighlight lang="v (vlang)">fn main() { |
|||
println(median([3, 1, 4, 1])) // prints 2 |
|||
println(median([3, 1, 4, 1, 5])) // prints 3 |
|||
} |
|||
fn median(aa []int) int { |
|||
mut a := aa.clone() |
|||
a.sort() |
|||
half := a.len / 2 |
|||
mut m := a[half] |
|||
if a.len%2 == 0 { |
|||
m = (m + a[half-1]) / 2 |
|||
} |
|||
return m |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
2 |
|||
3 |
|||
</pre> |
|||
If you use math.stats module the list parameter must be sorted |
|||
<syntaxhighlight lang="text">import math.stats |
|||
fn main() { |
|||
println(stats.median<int>([1, 1, 3, 4])) // prints 2 |
|||
println(stats.median<int>([1, 1, 3, 4, 5])) // prints 3 |
|||
}</syntaxhighlight> |
|||
=={{header|Wortel}}== |
|||
<syntaxhighlight lang="wortel">@let { |
|||
; iterative |
|||
med1 &l @let {a @sort l s #a i @/s 2 ?{%%s 2 ~/ 2 +`-i 1 a `i a `i a}} |
|||
; tacit |
|||
med2 ^(\~/2 @sum @(^(\&![#~f #~c] \~/2 \~-1 #) @` @id) @sort) |
|||
[[ |
|||
!med1 [4 2 5 2 1] |
|||
!med1 [4 5 2 1] |
|||
!med2 [4 2 5 2 1] |
|||
!med2 [4 5 2 1] |
|||
]] |
|||
}</syntaxhighlight> |
|||
Returns: <pre>[2 3 2 3]</pre> |
|||
=={{header|Wren}}== |
|||
{{libheader|Wren-sort}} |
|||
{{libheader|Wren-math}} |
|||
{{libheader|Wren-queue}} |
|||
<syntaxhighlight lang="wren">import "./sort" for Sort, Find |
|||
import "./math" for Nums |
|||
import "./queue" for PriorityQueue |
|||
var lists = [ |
|||
[5, 3, 4], |
|||
[3, 4, 1, -8.4, 7.2, 4, 1, 1.2] |
|||
] |
|||
for (l in lists) { |
|||
// sort and then find median |
|||
var l2 = Sort.merge(l) |
|||
System.print(Nums.median(l2)) |
|||
// using a priority queue |
|||
var pq = PriorityQueue.new() |
|||
for (e in l) pq.push(e, -e) |
|||
var c = pq.count |
|||
var v = pq.values |
|||
var m = (c % 2 == 1) ? v[(c/2).floor] : (v[c/2] + v[c/2-1])/2 |
|||
System.print(m) |
|||
// using quickselect |
|||
if (c % 2 == 1) { |
|||
System.print(Find.quick(l, (c/2).floor)) |
|||
} else { |
|||
var m1 = Find.quick(l, c/2-1) |
|||
var m2 = Find.quick(l, c/2) |
|||
System.print((m1 + m2)/2) |
|||
} |
|||
System.print() |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
4 |
|||
4 |
|||
4 |
|||
2.1 |
|||
2.1 |
|||
2.1 |
|||
</pre> |
|||
=={{header|XPL0}}== |
|||
<syntaxhighlight lang "XPL0">func real Median(Size, Array); \Return median value of Array |
|||
int Size; real Array; |
|||
int I, J, MinJ; |
|||
real Temp; |
|||
[for I:= 0 to Size/2 do \partial selection sort |
|||
[MinJ:= I; |
|||
for J:= I+1 to Size-1 do |
|||
if Array(J) < Array(MinJ) then MinJ:= J; |
|||
Temp:= Array(I); Array(I):= Array(MinJ); Array(MinJ):= Temp; |
|||
]; |
|||
if rem(Size/2) = 1 then return Array(Size/2) |
|||
else return (Array(Size/2-1) + Array(Size/2)) / 2.; |
|||
]; |
|||
[RlOut(0, Median(3, [5.0, 3.0, 4.0])); CrLf(0); |
|||
RlOut(0, Median(8, [3.0, 4.0, 1.0, -8.4, 7.2, 4.0, 1.0, 1.2])); CrLf(0); |
|||
]</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
4.00000 |
|||
2.10000 |
|||
</pre> |
|||
=={{header|Yabasic}}== |
|||
{{trans|Lua}} |
|||
<syntaxhighlight lang="yabasic">sub floor(x) |
|||
return int(x + .05) |
|||
end sub |
|||
sub ceil(x) |
|||
if x > int(x) x = x + 1 |
|||
return x |
|||
end sub |
|||
SUB ASort$(matriz$()) |
|||
local last, gap, first, tempi$, tempj$, i, j |
|||
last = arraysize(matriz$(), 1) |
|||
gap = floor(last / 10) + 1 |
|||
while(TRUE) |
|||
first = gap + 1 |
|||
for i = first to last |
|||
tempi$ = matriz$(i) |
|||
j = i - gap |
|||
while(TRUE) |
|||
tempj$ = matriz$(j) |
|||
if (tempi$ >= tempj$) then |
|||
j = j + gap |
|||
break |
|||
end if |
|||
matriz$(j+gap) = tempj$ |
|||
if j <= gap then |
|||
break |
|||
end if |
|||
j = j - gap |
|||
wend |
|||
matriz$(j) = tempi$ |
|||
next i |
|||
if gap = 1 then |
|||
return |
|||
else |
|||
gap = floor(gap / 3.5) + 1 |
|||
end if |
|||
wend |
|||
END SUB |
|||
sub median(numlist$) |
|||
local numlist$(1), n |
|||
n = token(numlist$, numlist$(), ", ") |
|||
ASort$(numlist$()) |
|||
if mod(n, 2) = 0 then return (val(numlist$(n / 2)) + val(numlist$(n / 2 + 1))) / 2 end if |
|||
return val(numlist$(ceil(n / 2))) |
|||
end sub |
|||
print median("4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2") // 4.4 |
|||
print median("4.1, 7.2, 1.7, 9.3, 4.4, 3.2") // 4.25 |
|||
</syntaxhighlight> |
|||
=={{header|zkl}}== |
|||
Using the [[Quickselect algorithm#zkl]] for O(n) time: |
|||
<syntaxhighlight lang="zkl">var quickSelect=Import("quickSelect").qselect; |
|||
fcn median(xs){ |
|||
n:=xs.len(); |
|||
if (n.isOdd) return(quickSelect(xs,n/2)); |
|||
( quickSelect(xs,n/2-1) + quickSelect(xs,n/2) )/2; |
|||
}</syntaxhighlight> |
|||
<syntaxhighlight lang="zkl">median(T( 5.1, 2.6, 6.2, 8.8, 4.6, 4.1 )); //-->4.85 |
|||
median(T( 5.1, 2.6, 8.8, 4.6, 4.1 )); //-->4.6</syntaxhighlight> |
|||
=={{header|Zoea}}== |
|||
<syntaxhighlight lang="zoea"> |
|||
program: median |
|||
case: 1 |
|||
input: [4,5,6,8,9] |
|||
output: 6 |
|||
case: 2 |
|||
input: [2,5,6] |
|||
output: 5 |
|||
case: 3 |
|||
input: [2,5,6,8] |
|||
output: 5.5 |
|||
</syntaxhighlight> |
|||
=={{header|Zoea Visual}}== |
|||
[http://zoea.co.uk/examples/zv-rc/Median.png Median] |
|||
=={{header|zonnon}}== |
|||
<syntaxhighlight lang="zonnon"> |
|||
module Averages; |
|||
type |
|||
Vector = array {math} * of real; |
|||
procedure Partition(var a: Vector; left, right: integer): integer; |
|||
var |
|||
pValue,aux: real; |
|||
store,i,pivot: integer; |
|||
begin |
|||
pivot := right; |
|||
pValue := a[pivot]; |
|||
aux := a[right];a[right] := a[pivot];a[pivot] := aux; (* a[pivot] <-> a[right] *) |
|||
store := left; |
|||
for i := left to right -1 do |
|||
if a[i] <= pValue then |
|||
aux := a[store];a[store] := a[i];a[i]:=aux; |
|||
inc(store) |
|||
end |
|||
end; |
|||
aux := a[right];a[right] := a[store]; a[store] := aux; |
|||
return store |
|||
end Partition; |
|||
(* QuickSelect algorithm *) |
|||
procedure Select(a: Vector; left,right,k: integer;var r: real); |
|||
var |
|||
pIndex, pDist : integer; |
|||
begin |
|||
if left = right then r := a[left]; return end; |
|||
pIndex := Partition(a,left,right); |
|||
pDist := pIndex - left + 1; |
|||
if pDist = k then |
|||
r := a[pIndex];return |
|||
elsif k < pDist then |
|||
Select(a,left, pIndex - 1, k, r) |
|||
else |
|||
Select(a,pIndex + 1, right, k - pDist, r) |
|||
end |
|||
end Select; |
|||
procedure Median(a: Vector): real; |
|||
var |
|||
idx: integer; |
|||
r1,r2 : real; |
|||
begin |
|||
idx := len(a) div 2 + 1; |
|||
r1 := 0.0;r2 := 0.0; |
|||
Select(a,0,len(a) - 1,idx,r1); |
|||
if odd(len(a)) then return r1 end; |
|||
Select(a,0,len(a) - 1,idx - 1,r2); |
|||
return (r1 + r2) / 2; |
|||
end Median; |
|||
var |
|||
ary: Vector; |
|||
r: real; |
|||
begin |
|||
ary := new Vector(3); |
|||
ary := [5.0,3.0,4.0]; |
|||
writeln(Median(ary):10:2); |
|||
ary := new Vector(4); |
|||
ary := [5.0,4.0,2.0,3.0]; |
|||
writeln(Median(ary):10:2); |
|||
ary := new Vector(8); |
|||
ary := [3.0,4.0,1.0,-8.4,7.2,4.0,1.0,1.2]; |
|||
writeln(Median(ary):10:2) |
|||
end Averages. |
|||
</syntaxhighlight> |
|||
<pre> |
|||
4 |
|||
3,5 |
|||
2,1 |
|||
</pre> |
Latest revision as of 22:06, 24 March 2024
You are encouraged to solve this task according to the task description, using any language you may know.
- Task
Write a program to find the median value of a vector of floating-point numbers.
The program need not handle the case where the vector is empty, but must handle the case where there are an even number of elements. In that case, return the average of the two middle values.
There are several approaches to this. One is to sort the elements, and then pick the element(s) in the middle.
Sorting would take at least O(n logn). Another approach would be to build a priority queue from the elements, and then extract half of the elements to get to the middle element(s). This would also take O(n logn). The best solution is to use the selection algorithm to find the median in O(n) time.
|
11l
F median(aray)
V srtd = sorted(aray)
V alen = srtd.len
R 0.5 * (srtd[(alen - 1) I/ 2] + srtd[alen I/ 2])
print(median([4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2]))
print(median([4.1, 7.2, 1.7, 9.3, 4.4, 3.2]))
- Output:
4.4 4.25
AArch64 Assembly
/* ARM assembly AARCH64 Raspberry PI 3B */
/* program averageMed64.s */
/* use quickselect look pseudo code in wikipedia quickselect */
/************************************/
/* Constantes */
/************************************/
/* for this file see task include a file in language AArch64 assembly*/
.include "../includeConstantesARM64.inc"
/*********************************/
/* Initialized data */
/*********************************/
.data
szMessResultValue: .asciz "Result : "
szCarriageReturn: .asciz "\n"
.align 4
TableNumber: .double 4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2
.equ NBELEMENTS, (. - TableNumber) / 8
TableNumber2: .double 4.1, 7.2, 1.7, 9.3, 4.4, 3.2
.equ NBELEMENTS2, (. - TableNumber2) / 8
/*********************************/
/* UnInitialized data */
/*********************************/
.bss
sZoneConv: .skip 24
sZoneConv1: .skip 24
/*********************************/
/* code section */
/*********************************/
.text
.global main
main: // entry of program
ldr x0,qAdrTableNumber // address number table
mov x1,#0 // index first item
mov x2,#NBELEMENTS -1 // index last item
bl searchMedian
ldr x0,qAdrTableNumber2 // address number table 2
mov x1,#0 // index first item
mov x2,#NBELEMENTS2 -1 // index last item
bl searchMedian
100: // standard end of the program
mov x0, #0 // return code
mov x8, #EXIT // request to exit program
svc #0 // perform the system call
qAdrszCarriageReturn: .quad szCarriageReturn
qAdrTableNumber: .quad TableNumber
qAdrTableNumber2: .quad TableNumber2
qAdrsZoneConv: .quad sZoneConv
qAdrszMessResultValue: .quad szMessResultValue
/***************************************************/
/* search median term in float array */
/***************************************************/
/* x0 contains the address of table */
/* x1 contains index of first item */
/* x2 contains index of last item */
searchMedian:
stp x1,lr,[sp,-16]! // save registers TODO: à revoir génération
stp x2,x3,[sp,-16]! // save registers
stp x4,x5,[sp,-16]! // save registers
mov x19,x0 // save array address
add x4,x1,x2
add x4,x4,#1 // sum numbers terms
tst x4,#1 // odd ?
bne 1f
lsr x3,x4,#1 // compute median index
bl select // call selection
fmov d0,x0 // save first result
sub x3,x3,#1 // second term
mov x0,x19
bl select // call selection
fmov d1,x0 // save 2ieme résult
fadd d0,d0,d1 // compute average two résults
mov x0,#2
fmov d1,x0
scvtf d1,d1 // conversion integer -> float
fdiv d0,d0,d1
b 2f
1: // even
lsr x3,x4,#1
bl select // call selection
fmov d0,x0
2:
ldr x0,qAdrsZoneConv // conversion float in decimal string
bl convertirFloat
mov x0,#3 // and display result
ldr x1,qAdrszMessResultValue
ldr x2,qAdrsZoneConv
ldr x3,qAdrszCarriageReturn
bl displayStrings
100: // end function
ldp x4,x5,[sp],16 // restaur 2 registers
ldp x2,x3,[sp],16 // restaur 2 registers
ldp x1,lr,[sp],16 // restaur 2 registers
ret
/***************************************************/
/* Appel récursif selection */
/***************************************************/
/* x0 contains the address of table */
/* x1 contains index of first item */
/* x2 contains index of last item */
/* x3 contains search index */
select:
stp x1,lr,[sp,-16]! // save registers
stp x2,x3,[sp,-16]! // save registers
stp x4,x5,[sp,-16]! // save registers
stp x6,x7,[sp,-16]! // save registers
mov x6,x3 // save search index
cmp x1,x2 // first = last ?
bne 1f
ldr x0,[x0,x1,lsl #3] // return value of first index
b 100f // yes -> end
1:
add x3,x1,x2
lsr x3,x3,#1 // compute median pivot
mov x4,x0 // save x0
mov x5,x2 // save x2
bl partition // cutting.quado 2 parts
cmp x6,x0 // pivot is ok ?
bne 2f
ldr x0,[x4,x0,lsl #3] // yes -> return value
b 100f
2:
bgt 3f
sub x2,x0,#1 // index partition - 1
mov x0,x4 // array address
mov x3,x6 // search index
bl select // select lower part
b 100f
3:
add x1,x0,#1 // index begin = index partition + 1
mov x0,x4 // array address
mov x2,x5 // last item
mov x3,x6 // search index
bl select // select higter part
100: // end function
ldp x6,x7,[sp],16 // restaur 2 registers
ldp x4,x5,[sp],16 // restaur 2 registers
ldp x2,x3,[sp],16 // restaur 2 registers
ldp x1,lr,[sp],16 // restaur 2 registers
ret // return to address lr x30
/******************************************************************/
/* Partition table elements */
/******************************************************************/
/* x0 contains the address of table */
/* x1 contains index of first item */
/* x2 contains index of last item */
/* x3 contains index of pivot */
partition:
stp x1,lr,[sp,-16]! // save registers
stp x2,x3,[sp,-16]! // save registers
stp x4,x5,[sp,-16]! // save registers
stp x6,x7,[sp,-16]! // save registers
ldr x4,[x0,x3,lsl #3] // load value of pivot
ldr x5,[x0,x2,lsl #3] // load value last index
str x5,[x0,x3,lsl #3] // swap value of pivot
str x4,[x0,x2,lsl #3] // and value last index
mov x3,x1 // init with first index
1: // begin loop
ldr x6,[x0,x3,lsl #3] // load value
cmp x6,x4 // compare loop value and pivot value
bge 2f
ldr x5,[x0,x1,lsl #3] // if < swap value table
str x6,[x0,x1,lsl #3]
str x5,[x0,x3,lsl #3]
add x1,x1,#1 // and increment index 1
2:
add x3,x3,#1 // increment index 2
cmp x3,x2 // end ?
blt 1b // no loop
ldr x5,[x0,x1,lsl #3] // swap value
str x4,[x0,x1,lsl #3]
str x5,[x0,x2,lsl #3]
mov x0,x1 // return index partition
100:
ldp x6,x7,[sp],16 // restaur 2 registers
ldp x4,x5,[sp],16 // restaur 2 registers
ldp x2,x3,[sp],16 // restaur 2 registers
ldp x1,lr,[sp],16 // restaur 2 registers
ret // return to address lr x30
/***************************************************/
/* display multi strings */
/* new version 24/05/2023 */
/***************************************************/
/* x0 contains number strings address */
/* x1 address string1 */
/* x2 address string2 */
/* x3 address string3 */
/* x4 address string4 */
/* x5 address string5 */
/* x6 address string5 */
/* x7 address string6 */
displayStrings: // INFO: displayStrings
stp x8,lr,[sp,-16]! // save registers
stp x2,fp,[sp,-16]! // save registers
add fp,sp,#32 // save paraméters address (4 registers saved * 8 bytes)
mov x8,x0 // save strings number
cmp x8,#0 // 0 string -> end
ble 100f
mov x0,x1 // string 1
bl affichageMess
cmp x8,#1 // number > 1
ble 100f
mov x0,x2
bl affichageMess
cmp x8,#2
ble 100f
mov x0,x3
bl affichageMess
cmp x8,#3
ble 100f
mov x0,x4
bl affichageMess
cmp x8,#4
ble 100f
mov x0,x5
bl affichageMess
cmp x8,#5
ble 100f
mov x0,x6
bl affichageMess
cmp x8,#6
ble 100f
mov x0,x7
bl affichageMess
100:
ldp x2,fp,[sp],16 // restaur registers
ldp x8,lr,[sp],16 // restaur registers
ret
/******************************************************************/
/* Conversion Float */
/******************************************************************/
/* d0 contains Float */
/* x0 contains address conversion area mini 20 charactèrs */
/* x0 return result length */
/* see https://blog.benoitblanchon.fr/lightweight-float-to-string/ */
convertirFloat:
stp x1,lr,[sp,-16]! // save registres
stp x2,x3,[sp,-16]! // save registres
stp x4,x5,[sp,-16]! // save registres
stp x6,x7,[sp,-16]! // save registres
stp x8,x9,[sp,-16]! // save registres
stp d1,d2,[sp,-16]! // save registres
mov x6,x0 // save area address
fmov x0,d0
mov x8,#0 // result length
mov x3,#'+'
strb w3,[x6] // signe + forcing
mov x2,x0
tbz x2,63,1f
mov x2,1
lsl x2,x2,63
bic x0,x0,x2
mov x3,#'-' // sign -
strb w3,[x6]
1:
adds x8,x8,#1 // next position
cmp x0,#0 // case 0 positive or negative
bne 2f
mov x3,#'0'
strb w3,[x6,x8] // store character 0
adds x8,x8,#1
strb wzr,[x6,x8] // store 0 final
mov x0,x8 // return length
b 100f
2:
ldr x2,iMaskExposant
mov x1,x0
and x1,x1,x2 // exposant
cmp x1,x2
bne 4f
tbz x0,51,3f // test bit 51 to zéro
mov x2,#'N' // case Nan. store byte no possible store integer
strb w2,[x6] // area no aligned
mov x2,#'a'
strb w2,[x6,#1]
mov x2,#'n'
strb w2,[x6,#2]
mov x2,#0 // 0 final
strb w2,[x6,#3]
mov x0,#3
b 100f
3: // case infini positive or négative
mov x2,#'I'
strb w2,[x6,x8]
adds x8,x8,#1
mov x2,#'n'
strb w2,[x6,x8]
adds x8,x8,#1
mov x2,#'f'
strb w2,[x6,x8]
adds x8,x8,#1
mov x2,#0
strb w2,[x6,x8]
mov x0,x8
b 100f
4:
bl normaliserFloat
mov x5,x0 // save exposant
fcvtzu d2,d0
fmov x0,d2 // part integer
scvtf d1,d2 // conversion float
fsub d1,d0,d1 // extraction part fractional
ldr d2,dConst1
fmul d1,d2,d1 // to crop it in full
fcvtzu d1,d1 // convertion integer
fmov x4,d1 // fract value
// conversion part integer to x0
mov x2,x6 // save address begin area
adds x6,x6,x8
mov x1,x6
bl conversion10
add x6,x6,x0
mov x3,#','
strb w3,[x6]
adds x6,x6,#1
mov x0,x4 // conversion part fractionnaire
mov x1,x6
bl conversion10SP
add x6,x6,x0
sub x6,x6,#1
// remove trailing zeros
5:
ldrb w0,[x6]
cmp w0,#'0'
bne 6f
sub x6,x6,#1
b 5b
6:
cmp w0,#','
bne 7f
sub x6,x6,#1
7:
cmp x5,#0 // if exposant = 0 no display
bne 8f
add x6,x6,#1
b 10f
8:
add x6,x6,#1
mov x3,#'E'
strb w3,[x6]
add x6,x6,#1
mov x0,x5 // conversion exposant
mov x3,x0
tbz x3,63,9f // exposant negative ?
neg x0,x0
mov x3,#'-'
strb w3,[x6]
adds x6,x6,#1
9:
mov x1,x6
bl conversion10
add x6,x6,x0
10:
strb wzr,[x6] // store 0 final
adds x6,x6,#1
mov x0,x6
subs x0,x0,x2 // retour de la longueur de la zone
subs x0,x0,#1 // sans le 0 final
100:
ldp d1,d2,[sp],16 // restaur registres
ldp x8,x9,[sp],16 // restaur registres
ldp x6,x7,[sp],16 // restaur registres
ldp x4,x5,[sp],16 // restaur registres
ldp x2,x3,[sp],16 // restaur registres
ldp x1,lr,[sp],16 // restaur registres
ret
iMaskExposant: .quad 0x7FF<<52
dConst1: .double 0f1E17
/***************************************************/
/* normaliser float */
/***************************************************/
/* x0 contain float value (always positive value and <> Nan) */
/* d0 return new value */
/* x0 return exposant */
normaliserFloat:
stp x1,lr,[sp,-16]! // save registers
fmov d0,x0 // value float
mov x0,#0 // exposant
ldr d1,dConstE7 // no normalisation for value < 1E7
fcmp d0,d1
blo 10f // if d0 < dConstE7
ldr d1,dConstE256
fcmp d0,d1
blo 1f
fdiv d0,d0,d1
adds x0,x0,#256
1:
ldr d1,dConstE128
fcmp d0,d1
blo 1f
fdiv d0,d0,d1
adds x0,x0,#128
1:
ldr d1,dConstE64
fcmp d0,d1
blo 1f
fdiv d0,d0,d1
adds x0,x0,#64
1:
ldr d1,dConstE32
fcmp d0,d1
blo 1f
fdiv d0,d0,d1
adds x0,x0,#32
1:
ldr d1,dConstE16
fcmp d0,d1
blo 2f
fdiv d0,d0,d1
adds x0,x0,#16
2:
ldr d1,dConstE8
fcmp d0,d1
blo 3f
fdiv d0,d0,d1
adds x0,x0,#8
3:
ldr d1,dConstE4
fcmp d0,d1
blo 4f
fdiv d0,d0,d1
adds x0,x0,#4
4:
ldr d1,dConstE2
fcmp d0,d1
blo 5f
fdiv d0,d0,d1
adds x0,x0,#2
5:
ldr d1,dConstE1
fcmp d0,d1
blo 10f
fdiv d0,d0,d1
adds x0,x0,#1
10:
ldr d1,dConstME5 // pas de normalisation pour les valeurs > 1E-5
fcmp d0,d1
bhi 100f // fin
ldr d1,dConstME255
fcmp d0,d1
bhi 11f
ldr d1,dConstE256
fmul d0,d0,d1
subs x0,x0,#256
11:
ldr d1,dConstME127
fcmp d0,d1
bhi 11f
ldr d1,dConstE128
fmul d0,d0,d1
subs x0,x0,#128
11:
ldr d1,dConstME63
fcmp d0,d1
bhi 11f
ldr d1,dConstE64
fmul d0,d0,d1
subs x0,x0,#64
11:
ldr d1,dConstME31
fcmp d0,d1
bhi 11f
ldr d1,dConstE32
fmul d0,d0,d1
subs x0,x0,#32
11:
ldr d1,dConstME15
fcmp d0,d1
bhi 12f
ldr d1,dConstE16
fmul d0,d0,d1
subs x0,x0,#16
12:
ldr d1,dConstME7
fcmp d0,d1
bhi 13f
ldr d1,dConstE8
fmul d0,d0,d1
subs x0,x0,#8
13:
ldr d1,dConstME3
fcmp d0,d1
bhi 14f
ldr d1,dConstE4
fmul d0,d0,d1
subs x0,x0,#4
14:
ldr d1,dConstME1
fcmp d0,d1
bhi 15f
ldr d1,dConstE2
fmul d0,d0,d1
subs x0,x0,#2
15:
ldr d1,dConstE0
fcmp d0,d1
bhi 100f
ldr d1,dConstE1
fmul d0,d0,d1
subs x0,x0,#1
100: // fin standard de la fonction
ldp x1,lr,[sp],16 // restaur registres
ret
.align 2
dConstE7: .double 0f1E7
dConstE256: .double 0f1E256
dConstE128: .double 0f1E128
dConstE64: .double 0f1E64
dConstE32: .double 0f1E32
dConstE16: .double 0f1E16
dConstE8: .double 0f1E8
dConstE4: .double 0f1E4
dConstE2: .double 0f1E2
dConstE1: .double 0f1E1
dConstME5: .double 0f1E-5
dConstME255: .double 0f1E-255
dConstME127: .double 0f1E-127
dConstME63: .double 0f1E-63
dConstME31: .double 0f1E-31
dConstME15: .double 0f1E-15
dConstME7: .double 0f1E-7
dConstME3: .double 0f1E-3
dConstME1: .double 0f1E-1
dConstE0: .double 0f1E0
/******************************************************************/
/* Décimal Conversion */
/******************************************************************/
/* x0 contain value et x1 address conversion area */
conversion10SP:
stp x1,lr,[sp,-16]! // save registers
stp x2,x3,[sp,-16]! // save registers
stp x4,x5,[sp,-16]! // save registers
mov x5,x1
mov x4,#16
mov x2,x0
mov x1,#10 // décimal conversion
1: // conversion loop
mov x0,x2 // copy begin number or quotient
udiv x2,x0,x1 // division by 10
msub x3,x1,x2,x0 // compute remainder
add x3,x3,#48 // compute digit
strb w3,[x5,x4] // store byte address area (x5) + offset (x4)
subs x4,x4,#1 // position precedente
bge 1b
strb wzr,[x5,16] // 0 final
100:
ldp x4,x5,[sp],16 // restaur registers
ldp x2,x3,[sp],16 // restaur registers
ldp x1,lr,[sp],16 // restaur registers
ret
/***************************************************/
/* ROUTINES INCLUDE */
/***************************************************/
/* for this file see task include a file in language AArch64 assembly*/
.include "../includeARM64.inc"
- Output:
Result : +4,4 Result : +4,25
Action!
INCLUDE "H6:REALMATH.ACT"
DEFINE PTR="CARD"
PROC Sort(PTR ARRAY a INT count)
INT i,j,minpos
REAL POINTER tmp
FOR i=0 TO count-2
DO
minpos=i
FOR j=i+1 TO count-1
DO
IF RealGreaterOrEqual(a(minpos),a(j)) THEN
minpos=j
FI
OD
IF minpos#i THEN
tmp=a(i)
a(i)=a(minpos)
a(minpos)=tmp
FI
OD
RETURN
PROC Median(PTR ARRAY a INT count REAL POINTER res)
IF count=0 THEN Break() FI
Sort(a,count)
IF (count&1)=0 THEN
RealAdd(a(count RSH 1-1),a(count RSH 1),res)
RealMult(res,half,res)
ELSE
RealAssign(a(count RSH 1),res)
FI
RETURN
PROC Test(PTR ARRAY a INT count)
INT i
REAL res
FOR i=0 TO count-1
DO
PrintR(a(i)) Put(32)
OD
Median(a,count,res)
Print("-> ")
PrintRE(res)
RETURN
PROC Main()
PTR ARRAY a(8)
REAL r1,r2,r3,r4,r5,r6,r7,r8
BYTE i
Put(125) PutE() ;clear the screen
MathInit()
ValR("3.2",r1) ValR("-4.1",r2)
ValR("0.6",r3) ValR("9.8",r4)
ValR("5.1",r5) ValR("-1.4",r6)
ValR("0.3",r7) ValR("2.2",r8)
FOR i=1 TO 8
DO
a(0)=r1 a(1)=r2 a(2)=r3 a(3)=r4
a(4)=r5 a(5)=r6 a(6)=r7 a(7)=r8
Test(a,i)
OD
RETURN
- Output:
Screenshot from Atari 8-bit computer
3.2 -> 3.2 3.2 -4.1 -> -0.45 3.2 -4.1 .6 -> .6 3.2 -4.1 .6 9.8 -> 1.9 3.2 -4.1 .6 9.8 5.1 -> 3.2 3.2 -4.1 .6 9.8 5.1 -1.4 -> 1.9 3.2 -4.1 .6 9.8 5.1 -1.4 .3 -> .6 3.2 -4.1 .6 9.8 5.1 -1.4 .3 2.2 -> 1.4
Ada
with Ada.Text_IO, Ada.Float_Text_IO;
procedure FindMedian is
f: array(1..10) of float := ( 4.4, 2.3, -1.7, 7.5, 6.6, 0.0, 1.9, 8.2, 9.3, 4.5 );
min_idx: integer;
min_val, median_val, swap: float;
begin
for i in f'range loop
min_idx := i;
min_val := f(i);
for j in i+1 .. f'last loop
if f(j) < min_val then
min_idx := j;
min_val := f(j);
end if;
end loop;
swap := f(i); f(i) := f(min_idx); f(min_idx) := swap;
end loop;
if f'length mod 2 /= 0 then
median_val := f( f'length/2+1 );
else
median_val := ( f(f'length/2) + f(f'length/2+1) ) / 2.0;
end if;
Ada.Text_IO.Put( "Median value: " );
Ada.Float_Text_IO.Put( median_val );
Ada.Text_IO.New_line;
end FindMedian;
ALGOL 68
INT max_elements = 1000000;
# Return the k-th smallest item in array x of length len #
PROC quick_select = (INT k, REF[]REAL x) REAL:
BEGIN
PROC swap = (INT a, b) VOID:
BEGIN
REAL t = x[a];
x[a] := x[b]; x[b] := t
END;
INT left := 1, right := UPB x;
INT pos, i;
REAL pivot;
WHILE left < right DO
pivot := x[k];
swap (k, right);
pos := left;
FOR i FROM left TO right DO
IF x[i] < pivot THEN
swap (i, pos);
pos +:= 1
FI
OD;
swap (right, pos);
IF pos = k THEN break FI;
IF pos < k THEN left := pos + 1
ELSE right := pos - 1
FI
OD;
break:
SKIP;
x[k]
END;
# Initialize random length REAL array with random doubles #
INT length = ENTIER (next random * max_elements);
[length]REAL x;
FOR i TO length DO
x[i] := (next random * 1e6 - 0.5e6)
OD;
REAL median :=
IF NOT ODD length THEN
# Even number of elements, median is average of middle two #
(quick_select (length % 2, x) + quick_select(length % 2 - 1, x)) / 2
ELSE
# select middle element #
quick_select(length % 2, x)
FI;
# Sanity testing of median #
INT less := 0, more := 0, eq := 0;
FOR i TO length DO
IF x[i] < median THEN less +:= 1
ELIF x[i] > median THEN more +:= 1
ELSE eq +:= 1
FI
OD;
print (("length: ", whole (length,0), new line, "median: ", median, new line,
"<: ", whole (less,0), new line,
">: ", whole (more, 0), new line,
"=: ", whole (eq, 0), new line))
Sample output:
length: 97738 median: -2.52550126608709e +3 <: 48868 >: 48870 =: 0
Amazing Hopper
#include <basico.h>
#proto cálculodemediana(_X_)
#synon _cálculodemediana obtenermedianade
algoritmo
decimales '2'
matrices 'a,b'
'4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2', enlistar en 'a'
'4.1, 7.2, 1.7, 9.3, 4.4, 3.2', enlistar en 'b'
arr.ordenar 'a'
arr.ordenar 'b'
"A=",a,NL,"Median: ", obtener mediana de 'a', NL
"B=",b,NL,"Median: ", obtener mediana de 'b', NL
finalmente imprime
terminar
subrutinas
cálculo de mediana (x)
dx=0
filas de 'x' ---copiar en 'dx'---
calcular si ( es par?, #( (x[ (dx/2) ]+x[ (dx/2)+1 ])/2 ),\
#( x[ dx/2+1 ] ) )
retornar
- Output:
A=1.70,3.20,4.10,4.40,5.60,7.20,9.30 Median: 4.40 B=1.70,3.20,4.10,4.40,7.20,9.30 Median: 4.25
AntLang
AntLang has a built-in median function.
median[list]
APL
median←{v←⍵[⍋⍵]⋄.5×v[⌈¯1+.5×⍴v]+v[⌊.5×⍴v]} ⍝ Assumes ⎕IO←0
First, the input vector ⍵ is sorted with ⍵[⍋⍵] and the result placed in v. If the dimension ⍴v of v is odd, then both ⌈¯1+.5×⍴v and ⌊.5×⍴v give the index of the middle element. If ⍴v is even, ⌈¯1+.5×⍴v and ⌊.5×⍴v give the indices of the two middle-most elements. In either case, the average of the elements at these indices gives the median.
Note that the index origin ⎕IO is assumed zero. To set it to zero use:
⎕IO←0
If you prefer an index origin of 1, use this code instead:
⎕IO←1
median←{v←⍵[⍋⍵] ⋄ 0.5×v[⌈0.5×⍴v]+v[⌊1+0.5×⍴v]}
This code was tested with ngn/apl and Dyalog 12.1. You can try this function online with ngn/apl. Note that ngn/apl currently only supports index origin 0. Examples:
median 1 5 3 6 4 2 3.5 median 1 5 3 2 4 3 median 4.4 2.3 ¯1.7 7.5 6.6 0.0 1.9 8.2 9.3 4.5 4.45 median 4.1 4 1.2 6.235 7868.33 4.1 median 4.1 5.6 7.2 1.7 9.3 4.4 3.2 4.4 median 4.1 7.2 1.7 9.3 4.4 3.2 4.25
Caveats: To keep it simple, no input validation is done. If you input a vector with zero elements (e.g., ⍳0), you get an INDEX ERROR. If you input a vector with 1 element, you get a RANK ERROR. Only (rank 1) numeric vectors of dimension 2 or more are supported. If you input a (rank 2 or more) matrix, you get a RANK ERROR. If you input a string (vector of chars), you get a DOMAIN ERROR:
median ⍳0 INDEX ERROR median 66.6 RANK ERROR median (2 2)⍴⍳4 ⍝ 2x2 matrix RANK ERROR median 'HELLO' DOMAIN ERROR
AppleScript
By iteration
set alist to {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0}
set med to medi(alist)
on medi(alist)
set temp to {}
set lcount to count alist
if lcount is equal to 2 then
return ((item 1 of alist) + (item 2 of alist)) / 2
else if lcount is less than 2 then
return item 1 of alist
else --if lcount is greater than 2
set min to findmin(alist)
set max to findmax(alist)
repeat with x from 1 to lcount
if x is not equal to min and x is not equal to max then set end of temp to item x of alist
end repeat
set med to medi(temp)
end if
return med
end medi
on findmin(alist)
set min to 1
set alength to count every item of alist
repeat with x from 1 to alength
if item x of alist is less than item min of alist then set min to x
end repeat
return min
end findmin
on findmax(alist)
set max to 1
set alength to count every item of alist
repeat with x from 1 to alength
if item x of alist is greater than item max of alist then set max to x
end repeat
return max
end findmax
- Output:
4.5
Composing functionally
Using a quick select algorithm:
-- MEDIAN ---------------------------------------------------------------------
-- median :: [Num] -> Num
on median(xs)
-- nth :: [Num] -> Int -> Maybe Num
script nth
on |λ|(xxs, n)
if length of xxs > 0 then
set {x, xs} to uncons(xxs)
script belowX
on |λ|(y)
y < x
end |λ|
end script
set {ys, zs} to partition(belowX, xs)
set k to length of ys
if k = n then
x
else
if k > n then
|λ|(ys, n)
else
|λ|(zs, n - k - 1)
end if
end if
else
missing value
end if
end |λ|
end script
set n to length of xs
if n > 0 then
tell nth
if n mod 2 = 0 then
(|λ|(xs, n div 2) + |λ|(xs, (n div 2) - 1)) / 2
else
|λ|(xs, n div 2)
end if
end tell
else
missing value
end if
end median
-- TEST -----------------------------------------------------------------------
on run
map(median, [¬
[], ¬
[5, 3, 4], ¬
[5, 4, 2, 3], ¬
[3, 4, 1, -8.4, 7.2, 4, 1, 1.2]])
--> {missing value, 4, 3.5, 2.1}
end run
-- GENERIC FUNCTIONS ----------------------------------------------------------
-- map :: (a -> b) -> [a] -> [b]
on map(f, xs)
tell mReturn(f)
set lng to length of xs
set lst to {}
repeat with i from 1 to lng
set end of lst to |λ|(item i of xs, i, xs)
end repeat
return lst
end tell
end map
-- Lift 2nd class handler function into 1st class script wrapper
-- mReturn :: Handler -> Script
on mReturn(f)
if class of f is script then
f
else
script
property |λ| : f
end script
end if
end mReturn
-- partition :: predicate -> List -> (Matches, nonMatches)
-- partition :: (a -> Bool) -> [a] -> ([a], [a])
on partition(f, xs)
tell mReturn(f)
set lst to {{}, {}}
repeat with x in xs
set v to contents of x
set end of item ((|λ|(v) as integer) + 1) of lst to v
end repeat
end tell
{item 2 of lst, item 1 of lst}
end partition
-- uncons :: [a] -> Maybe (a, [a])
on uncons(xs)
if length of xs > 0 then
{item 1 of xs, rest of xs}
else
missing value
end if
end uncons
- Output:
{missing value, 4, 3.5, 2.1}
Quickselect
-- Return the median value of items l thru r of a list of numbers.
on getMedian(theList, l, r)
if (theList is {}) then return theList
script o
property lst : theList's items l thru r -- Copy of the range to be searched.
end script
set rangeLength to (r - l + 1)
set m to (rangeLength + 1) div 2 -- Central position in the range copy, or the leftmost of two.
set {l, r} to {1, rangeLength} -- Outer partition indices.
set previousR to r -- Reminder of previous r.
repeat -- quickselect repeat
set pivot to o's lst's item ((l + r) div 2)
set i to l
set j to r
repeat until (i > j)
set lv to o's lst's item i
repeat while (lv < pivot)
set i to i + 1
set lv to o's lst's item i
end repeat
set rv to o's lst's item j
repeat while (rv > pivot)
set j to j - 1
set rv to o's lst's item j
end repeat
if (i > j) then
else
set o's lst's item i to rv
set o's lst's item j to lv
set i to i + 1
set j to j - 1
end if
end repeat
-- If i and j have crossed at m, item m's the median value.
-- Otherwise reset to partition the partition containing m.
if (j < m) then
if (i > m) then exit repeat
set l to i
else
set previousR to r
set r to j
end if
end repeat
set median to item m of o's lst
-- If the range has an even number of items, find the lowest value to the right of m and average it
-- with the median just obtained. We only need to search to the end of the range just partitioned —
-- unless that's where m is, in which case to end of the most recent extent beyond that (if any).
if (rangeLength mod 2 is 0) then
set median2 to item i of o's lst
if (r = m) then set r to previousR
repeat with i from (i + 1) to r
set v to item i of o's lst
if (v < median2) then set median2 to v
end repeat
set median to (median + median2) / 2
end if
return median
end getMedian
-- Demo:
local testList
set testList to {}
repeat with i from 1 to 8
set end of testList to (random number 500) / 5
end repeat
return {|numbers|:testList, median:getMedian(testList, 1, (count testList))}
- Output:
{|numbers|:{71.6, 44.8, 45.8, 28.6, 96.8, 98.4, 42.4, 97.8}, median:58.7}
Partial heap sort
-- Based on the heap sort algorithm ny J.W.J. Williams.
on getMedian(theList, l, r)
script o
property lst : theList's items l thru r -- Copy of the range to be searched.
-- Sift a value down into the heap from a given root node.
on siftDown(siftV, root, endOfHeap)
set child to root * 2
repeat until (child comes after endOfHeap)
set childV to item child of my lst
if (child comes before endOfHeap) then
set child2 to child + 1
set child2V to item child2 of my lst
if (child2V > childV) then
set child to child2
set childV to child2V
end if
end if
if (childV > siftV) then
set item root of my lst to childV
set root to child
set child to root * 2
else
exit repeat
end if
end repeat
set item root of my lst to siftV
end siftDown
end script
set r to (r - l + 1)
-- Arrange the sort range into a "heap" with its "top" at the leftmost position.
repeat with i from (r + 1) div 2 to 1 by -1
tell o to siftDown(item i of its lst, i, r)
end repeat
-- Work the heap as if extracting the values that would come after the median when sorted.
repeat with endOfHeap from r to (r - (r + 1) div 2 + 2) by -1
tell o to siftDown(item endOfHeap of its lst, 1, endOfHeap - 1)
end repeat
-- Extract the median itself, now at the top of the heap.
set median to beginning of o's lst
-- If the range has an even number of items, also get the value that would come before the median
-- just obtained. By now it's either the second or third item in the heap, so no need to sift for it.
-- Get the average if it and the median.
if (r mod 2 is 0) then
set median2 to item 2 of o's lst
if ((r > 2) and (item 3 of o's lst > median2)) then set median2 to item 3 of o's lst
set median to (median + median2) / 2
end if
return median
end getMedian
-- Demo:
local testList
set testList to {}
repeat with i from 1 to 8
set end of testList to (random number 500) / 5
end repeat
return {|numbers|:testList, median:getMedian(testList, 1, (count testList))}
- Output:
{|numbers|:{28.0, 75.6, 21.4, 51.8, 79.6, 25.0, 95.4, 31.2}, median:41.5}
Applesoft BASIC
100 REMMEDIAN
110 K = INT(L/2) : GOSUB 150
120 R = X(K)
130 IF L - 2 * INT (L / 2) THEN R = (R + X(K + 1)) / 2
140 RETURN
150 REMQUICK SELECT
160 LT = 0:RT = L - 1
170 FOR J = LT TO RT STEP 0
180 PT = X(K)
190 P1 = K:P2 = RT: GOSUB 300
200 P = LT
210 FOR I = P TO RT - 1
220 IF X(I) < PT THEN P1 = I:P2 = P: GOSUB 300:P = P + 1
230 NEXT I
240 P1 = RT:P2 = P: GOSUB 300
250 IF P = K THEN RETURN
260 IF P < K THEN LT = P + 1
270 IF P > = K THEN RT = P - 1
280 NEXT J
290 RETURN
300 REMSWAP
310 H = X(P1):X(P1) = X(P2)
320 X(P2) = H: RETURN
Example:
X(0)=4.4 : X(1)=2.3 : X(2)=-1.7 : X(3)=7.5 : X(4)=6.6 : X(5)=0.0 : X(6)=1.9 : X(7)=8.2 : X(8)=9.3 : X(9)=4.5 : X(10)=-11.7
L = 11 : GOSUB 100MEDIAN
? R
Output:
5.95
ARM Assembly
/* ARM assembly Raspberry PI */
/* program averageMed.s */
/* use quickselect look pseudo code in wikipedia quickselect */
/************************************/
/* Constantes */
/************************************/
/* for constantes see task include a file in arm assembly */
.include "../constantes.inc"
/*********************************/
/* Initialized data */
/*********************************/
.data
szMessResultValue: .asciz "Result : "
szCarriageReturn: .asciz "\n"
.align 4
TableNumber: .float 4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2
.equ NBELEMENTS, (. - TableNumber) / 4
TableNumber2: .float 4.1, 7.2, 1.7, 9.3, 4.4, 3.2
.equ NBELEMENTS2, (. - TableNumber2) / 4
/*********************************/
/* UnInitialized data */
/*********************************/
.bss
sZoneConv: .skip 24
sZoneConv1: .skip 24
/*********************************/
/* code section */
/*********************************/
.text
.global main
main: @ entry of program
ldr r0,iAdrTableNumber @ address number table
mov r1,#0 @ index first item
mov r2,#NBELEMENTS -1 @ index last item
bl searchMedian
ldr r0,iAdrTableNumber2 @ address number table 2
mov r1,#0 @ index first item
mov r2,#NBELEMENTS2 -1 @ index last item
bl searchMedian
100: @ standard end of the program
mov r0, #0 @ return code
mov r7, #EXIT @ request to exit program
svc #0 @ perform the system call
iAdrszCarriageReturn: .int szCarriageReturn
iAdrTableNumber: .int TableNumber
iAdrTableNumber2: .int TableNumber2
iAdrsZoneConv: .int sZoneConv
iAdrszMessResultValue: .int szMessResultValue
/***************************************************/
/* search median term in float array */
/***************************************************/
/* r0 contains the address of table */
/* r1 contains index of first item */
/* r2 contains index of last item */
searchMedian:
push {r1-r5,lr} @ save registers
mov r5,r0 @ save array address
add r4,r1,r2
add r4,r4,#1 @ sum numbers terms
tst r4,#1 @ odd ?
bne 1f
lsr r3,r4,#1 @ compute median index
bl select @ call selection
vmov s0,r0 @ save first result
sub r3,r3,#1 @ second term
mov r0,r5
bl select @ call selection
vmov s1,r0 @ save 2ieme résult
vadd.f32 s0,s1 @ compute average two résults
mov r0,#2
vmov s1,r0
vcvt.f32.u32 s1,s1 @ conversion integer -> float
vdiv.f32 s0,s0,s1
b 2f
1: @ even
lsr r3,r4,#1
bl select @ call selection
vmov s0,r0
2:
ldr r0,iAdrsZoneConv @ conversion float in decimal string
bl convertirFloat
mov r0,#3 @ and display result
ldr r1,iAdrszMessResultValue
ldr r2,iAdrsZoneConv
ldr r3,iAdrszCarriageReturn
bl displayStrings
100: @ end function
pop {r1-r5,pc} @ restaur register
/***************************************************/
/* Appel récursif selection */
/***************************************************/
/* r0 contains the address of table */
/* r1 contains index of first item */
/* r2 contains index of last item */
/* r3 contains search index */
/* r0 return final value in float */
/* remark : the final result is a float returned in r0 register */
select:
push {r1-r6,lr} @ save registers
mov r6,r3 @ save search index
cmp r1,r2 @ first = last ?
ldreq r0,[r0,r1,lsl #2] @ return value of first index
beq 100f @ yes -> end
add r3,r1,r2
lsr r3,r3,#1 @ compute median pivot
mov r4,r0 @ save r0
mov r5,r2 @ save r2
bl partition @ cutting into 2 parts
cmp r6,r0 @ pivot is ok ?
ldreq r0,[r4,r0,lsl #2] @ return value
beq 100f
bgt 1f
sub r2,r0,#1 @ index partition - 1
mov r0,r4 @ array address
mov r3,r6 @ search index
bl select @ select lower part
b 100f
1:
add r1,r0,#1 @ index begin = index partition + 1
mov r0,r4 @ array address
mov r2,r5 @ last item
mov r3,r6 @ search index
bl select @ select higter part
100: @ end function
pop {r1-r6,pc} @ restaur register
/******************************************************************/
/* Partition table elements */
/******************************************************************/
/* r0 contains the address of table */
/* r1 contains index of first item */
/* r2 contains index of last item */
/* r3 contains index of pivot */
partition:
push {r1-r6,lr} @ save registers
ldr r4,[r0,r3,lsl #2] @ load value of pivot
ldr r5,[r0,r2,lsl #2] @ load value last index
str r5,[r0,r3,lsl #2] @ swap value of pivot
str r4,[r0,r2,lsl #2] @ and value last index
mov r3,r1 @ init with first index
1: @ begin loop
ldr r6,[r0,r3,lsl #2] @ load value
cmp r6,r4 @ compare loop value and pivot value
ldrlt r5,[r0,r1,lsl #2] @ if < swap value table
strlt r6,[r0,r1,lsl #2]
strlt r5,[r0,r3,lsl #2]
addlt r1,#1 @ and increment index 1
add r3,#1 @ increment index 2
cmp r3,r2 @ end ?
blt 1b @ no loop
ldr r5,[r0,r1,lsl #2] @ swap value
str r4,[r0,r1,lsl #2]
str r5,[r0,r2,lsl #2]
mov r0,r1 @ return index partition
100:
pop {r1-r6,pc}
/***************************************************/
/* display multi strings */
/***************************************************/
/* r0 contains number strings address */
/* r1 address string1 */
/* r2 address string2 */
/* r3 address string3 */
/* other address on the stack */
/* thinck to add number other address * 4 to add to the stack */
displayStrings: @ INFO: displayStrings
push {r1-r4,fp,lr} @ save des registres
add fp,sp,#24 @ save paraméters address (6 registers saved * 4 bytes)
mov r4,r0 @ save strings number
cmp r4,#0 @ 0 string -> end
ble 100f
mov r0,r1 @ string 1
bl affichageMess
cmp r4,#1 @ number > 1
ble 100f
mov r0,r2
bl affichageMess
cmp r4,#2
ble 100f
mov r0,r3
bl affichageMess
cmp r4,#3
ble 100f
mov r3,#3
sub r2,r4,#4
1: @ loop extract address string on stack
ldr r0,[fp,r2,lsl #2]
bl affichageMess
subs r2,#1
bge 1b
100:
pop {r1-r4,fp,pc}
/******************************************************************/
/* Conversion Float */
/******************************************************************/
/* s0 contains Float */
/* r0 contains address conversion area mini 20 charactèrs*/
/* r0 return result length */
/* see https://blog.benoitblanchon.fr/lightweight-float-to-string/ */
convertirFloat:
push {r1-r7,lr}
vpush {s0-s2}
mov r6,r0 @ save area address
vmov r0,s0
mov r1,#0
vmov s1,r1
movs r7,#0 @ result length
movs r3,#'+'
strb r3,[r6] @ sign + forcing
mov r2,r0
lsls r2,#1 @ extraction bit 31
bcc 1f @ positive ?
lsrs r0,r2,#1 @ raz sign if negative
movs r3,#'-' @ sign -
strb r3,[r6]
1:
adds r7,#1 @ next position
cmp r0,#0 @ case of positive or negative 0
bne 2f
movs r3,#'0'
strb r3,[r6,r7] @ store character 0
adds r7,#1 @ next position
movs r3,#0
strb r3,[r6,r7] @ store 0 final
mov r0,r7 @ return length
b 100f @ and end
2:
ldr r2,iMaskExposant
mov r1,r0
ands r1,r2 @ exposant = 255 ?
cmp r1,r2
bne 4f
lsls r0,#10 @ bit 22 à 0 ?
bcc 3f @ yes
movs r2,#'N' @ case of Nan. store byte, if not possible store int
strb r2,[r6] @ area no aligned
movs r2,#'a'
strb r2,[r6,#1]
movs r2,#'n'
strb r2,[r6,#2]
movs r2,#0 @ 0 final
strb r2,[r6,#3]
movs r0,#3 @ return length 3
b 100f
3: @ case infini positive or négative
movs r2,#'I'
strb r2,[r6,r7]
adds r7,#1
movs r2,#'n'
strb r2,[r6,r7]
adds r7,#1
movs r2,#'f'
strb r2,[r6,r7]
adds r7,#1
movs r2,#0
strb r2,[r6,r7]
mov r0,r7
b 100f
4:
bl normaliserFloat
mov r5,r0 @ save exposant
VCVT.U32.f32 s2,s0 @ integer value of integer part
vmov r0,s2 @ integer part
VCVT.F32.U32 s1,s2 @ conversion float
vsub.f32 s1,s0,s1 @ extraction fract part
vldr s2,iConst1
vmul.f32 s1,s2,s1 @ to crop it in full
VCVT.U32.f32 s1,s1 @ integer conversion
vmov r4,s1 @ fract value
@ integer conversion in r0
mov r2,r6 @ save address area begin
adds r6,r7
mov r1,r6
bl conversion10
add r6,r0
movs r3,#','
strb r3,[r6]
adds r6,#1
mov r0,r4 @ conversion fractional part
mov r1,r6
bl conversion10SP @ spécial routine with conservation begin 0
add r6,r0
subs r6,#1
@ remove trailing zeros
5:
ldrb r0,[r6]
cmp r0,#'0'
bne 6f
subs r6,#1
b 5b
6:
cmp r0,#','
bne 7f
subs r6,#1
7:
adds r6,#1
movs r3,#'E'
strb r3,[r6]
adds r6,#1
mov r0,r5 @ conversion exposant
mov r3,r0
lsls r3,#1
bcc 4f
rsbs r0,r0,#0
movs r3,#'-'
strb r3,[r6]
adds r6,#1
4:
mov r1,r6
bl conversion10
add r6,r0
movs r3,#0
strb r3,[r6]
adds r6,#1
mov r0,r6
subs r0,r2 @ return length result
subs r0,#1 @ - 0 final
100:
vpop {s0-s2}
pop {r1-r7,pc}
iMaskExposant: .int 0xFF<<23
iConst1: .float 0f1E9
/***************************************************/
/* normaliser float */
/***************************************************/
/* r0 contain float value (always positive value and <> Nan) */
/* s0 return new value */
/* r0 return exposant */
normaliserFloat:
push {lr} @ save registre
vmov s0,r0 @ value float
movs r0,#0 @ exposant
vldr s1,iConstE7 @ no normalisation for value < 1E7
vcmp.f32 s0,s1
vmrs APSR_nzcv,FPSCR
blo 10f @ if s0 < iConstE7
vldr s1,iConstE32
vcmp.f32 s0,s1
vmrs APSR_nzcv,FPSCR
blo 1f
vldr s1,iConstE32
vdiv.f32 s0,s0,s1
adds r0,#32
1:
vldr s1,iConstE16
vcmp.f32 s0,s1
vmrs APSR_nzcv,FPSCR
blo 2f
vldr s1,iConstE16
vdiv.f32 s0,s0,s1
adds r0,#16
2:
vldr s1,iConstE8
vcmp.f32 s0,s1
vmrs APSR_nzcv,FPSCR
blo 3f
vldr s1,iConstE8
vdiv.f32 s0,s0,s1
adds r0,#8
3:
vldr s1,iConstE4
vcmp.f32 s0,s1
vmrs APSR_nzcv,FPSCR
blo 4f
vldr s1,iConstE4
vdiv.f32 s0,s0,s1
adds r0,#4
4:
vldr s1,iConstE2
vcmp.f32 s0,s1
vmrs APSR_nzcv,FPSCR
blo 5f
vldr s1,iConstE2
vdiv.f32 s0,s0,s1
adds r0,#2
5:
vldr s1,iConstE1
vcmp.f32 s0,s1
vmrs APSR_nzcv,FPSCR
blo 10f
vldr s1,iConstE1
vdiv.f32 s0,s0,s1
adds r0,#1
10:
vldr s1,iConstME5 @ pas de normalisation pour les valeurs > 1E-5
vcmp.f32 s0,s1
vmrs APSR_nzcv,FPSCR
bhi 100f
vldr s1,iConstME31
vcmp.f32 s0,s1
vmrs APSR_nzcv,FPSCR
bhi 11f
vldr s1,iConstE32
vmul.f32 s0,s0,s1
subs r0,#32
11:
vldr s1,iConstME15
vcmp.f32 s0,s1
vmrs APSR_nzcv,FPSCR
bhi 12f
vldr s1,iConstE16
vmul.f32 s0,s0,s1
subs r0,#16
12:
vldr s1,iConstME7
vcmp.f32 s0,s1
vmrs APSR_nzcv,FPSCR
bhi 13f
vldr s1,iConstE8
vmul.f32 s0,s0,s1
subs r0,#8
13:
vldr s1,iConstME3
vcmp.f32 s0,s1
vmrs APSR_nzcv,FPSCR
bhi 14f
vldr s1,iConstE4
vmul.f32 s0,s0,s1
subs r0,#4
14:
vldr s1,iConstME1
vcmp.f32 s0,s1
vmrs APSR_nzcv,FPSCR
bhi 15f
vldr s1,iConstE2
vmul.f32 s0,s0,s1
subs r0,#2
15:
vldr s1,iConstE0
vcmp.f32 s0,s1
vmrs APSR_nzcv,FPSCR
bhi 100f
vldr s1,iConstE1
vmul.f32 s0,s0,s1
subs r0,#1
100: @ fin standard de la fonction
pop {pc} @ restaur des registres
.align 2
iConstE7: .float 0f1E7
iConstE32: .float 0f1E32
iConstE16: .float 0f1E16
iConstE8: .float 0f1E8
iConstE4: .float 0f1E4
iConstE2: .float 0f1E2
iConstE1: .float 0f1E1
iConstME5: .float 0f1E-5
iConstME31: .float 0f1E-31
iConstME15: .float 0f1E-15
iConstME7: .float 0f1E-7
iConstME3: .float 0f1E-3
iConstME1: .float 0f1E-1
iConstE0: .float 0f1E0
/******************************************************************/
/* Décimal Conversion */
/******************************************************************/
/* r0 contain value et r1 address conversion area */
conversion10SP:
push {r1-r6,lr} @ save registers
mov r5,r1
mov r4,#8
mov r2,r0
mov r1,#10 @ conversion decimale
1: @ begin loop
mov r0,r2 @ copy number or quotients
bl division @ r0 dividende r1 divisor r2 quotient r3 remainder
add r3,#48 @ compute digit
strb r3,[r5,r4] @ store byte area address (r5) + offset (r4)
subs r4,r4,#1 @ position précedente
bge 1b @ and loop if not < zero
mov r0,#8
mov r3,#0
strb r3,[r5,r0] @ store 0 final
100:
pop {r1-r6,pc} @ restaur registers
/***************************************************/
/* ROUTINES INCLUDE */
/***************************************************/
/* for this file see task include a file in language ARM assembly */
.include "../affichage.inc"
- Output:
Result : +4,40000009E0 Result : +4,25E0
Arturo
arr: [1 2 3 4 5 6 7]
arr2: [1 2 3 4 5 6]
print median arr
print median arr2
- Output:
4 3.5
AutoHotkey
Takes the lower of the middle two if length is even
seq = 4.1, 7.2, 1.7, 9.3, 4.4, 3.2, 5
MsgBox % median(seq, "`,") ; 4.1
median(seq, delimiter)
{
Sort, seq, ND%delimiter%
StringSplit, seq, seq, % delimiter
median := Floor(seq0 / 2)
Return seq%median%
}
AWK
AWK arrays can be passed as parameters, but not returned, so they are usually global.
#!/usr/bin/awk -f
BEGIN {
d[1] = 3.0
d[2] = 4.0
d[3] = 1.0
d[4] = -8.4
d[5] = 7.2
d[6] = 4.0
d[7] = 1.0
d[8] = 1.2
showD("Before: ")
gnomeSortD()
showD("Sorted: ")
printf "Median: %f\n", medianD()
exit
}
function medianD( len, mid) {
len = length(d)
mid = int(len/2) + 1
if (len % 2) return d[mid]
else return (d[mid] + d[mid-1]) / 2.0
}
function gnomeSortD( i) {
for (i = 2; i <= length(d); i++) {
if (d[i] < d[i-1]) gnomeSortBackD(i)
}
}
function gnomeSortBackD(i, t) {
for (; i > 1 && d[i] < d[i-1]; i--) {
t = d[i]
d[i] = d[i-1]
d[i-1] = t
}
}
function showD(p, i) {
printf p
for (i = 1; i <= length(d); i++) {
printf d[i] " "
}
print ""
}
Example output:
Before: 3 4 1 -8.4 7.2 4 1 1.2 Sorted: -8.4 1 1 1.2 3 4 4 7.2 Median: 2.100000
BaCon
DECLARE a[] = { 4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2 } TYPE FLOATING
DECLARE b[] = { 4.1, 7.2, 1.7, 9.3, 4.4, 3.2 } TYPE FLOATING
DEF FN Dim(x) = SIZEOF(x) / SIZEOF(double)
DEF FN Median(x) = IIF(ODD(Dim(x)), x[(Dim(x)-1)/2], (x[Dim(x)/2-1]+x[Dim(x)/2])/2 )
SORT a
PRINT "Median of a: ", Median(a)
SORT b
PRINT "Median of b: ", Median(b)
- Output:
Median of a: 4.4 Median of b: 4.25
BASIC
This uses the Quicksort function described at Quicksort#BASIC, with arr()
's type changed to SINGLE
.
Note that in order to truly work with the Windows versions of PowerBASIC, the module-level code must be contained inside FUNCTION PBMAIN
. Similarly, in order to work under Visual Basic, the same module-level code must be contained with Sub Main
.
DECLARE FUNCTION median! (vector() AS SINGLE)
DIM vec1(10) AS SINGLE, vec2(11) AS SINGLE, n AS INTEGER
RANDOMIZE TIMER
FOR n = 0 TO 10
vec1(n) = RND * 100
vec2(n) = RND * 100
NEXT
vec2(11) = RND * 100
PRINT median(vec1())
PRINT median(vec2())
FUNCTION median! (vector() AS SINGLE)
DIM lb AS INTEGER, ub AS INTEGER, L0 AS INTEGER
lb = LBOUND(vector)
ub = UBOUND(vector)
REDIM v(lb TO ub) AS SINGLE
FOR L0 = lb TO ub
v(L0) = vector(L0)
NEXT
quicksort v(), lb, ub
IF ((ub - lb + 1) MOD 2) THEN
median = v((ub + lb) / 2)
ELSE
median = (v(INT((ub + lb) / 2)) + v(INT((ub + lb) / 2) + 1)) / 2
END IF
END FUNCTION
See also: BBC BASIC, Liberty BASIC, PureBasic, TI-83 BASIC, TI-89 BASIC.
BBC BASIC
INSTALL @lib$+"SORTLIB"
Sort% = FN_sortinit(0,0)
DIM a(6), b(5)
a() = 4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2
b() = 4.1, 7.2, 1.7, 9.3, 4.4, 3.2
PRINT "Median of a() is " ; FNmedian(a())
PRINT "Median of b() is " ; FNmedian(b())
END
DEF FNmedian(a())
LOCAL C%
C% = DIM(a(),1) + 1
CALL Sort%, a(0)
= (a(C% DIV 2) + a((C%-1) DIV 2)) / 2
Output:
Median of a() is 4.4 Median of b() is 4.25
BQN
A tacit definition from BQNcrate which sorts and takes the middle elements of the array.
Median ← (+´÷≠)∧⊏˜2⌊∘÷˜¯1‿0+≠ Median 5.961475‿2.025856‿7.262835‿1.814272‿2.281911‿4.854716
3.5683135
Bracmat
Each number is packaged in a little structure and these structures are accumulated in a sum. Bracmat keeps sums sorted, so the median is the term in the middle of the list, or the average of the two terms in the middle of the list. Notice that the input is converted to Bracmat's internal number representation, rational numbers, before being sorted. The output is converted back to 'double' variables. That last conversion is lossy.
( ( median
= begin decimals end int list
, med med1 med2 num number
. ( convertToRational
=
. new$(UFP,'(.$arg:?V))
: ?ufp
& (ufp..go)$
& (ufp..export)$(Q.V)
)
& 0:?list
& whl
' ( !arg:%?number ?arg
& convertToRational$!number:?rationalnumber
& (!rationalnumber.)+!list:?list
)
& !list:?+[?end
& ( !end*1/2:~/
& !list
: ?
+ [!(=1/2*!end+-1)
+ (?med1.?)
+ (?med2.?)
+ ?
& !med1*1/2+!med2*1/2:?med
| !list:?+[(div$(1/2*!end,1))+(?med.)+?
)
& (new$(UFP,'(.$med)).go)$
)
& out$(median$("4.1" 4 "1.2" "6.235" "7868.33"))
& out
$ ( median
$ ( "4.4"
"2.3"
"-1.7"
"7.5"
"6.6"
"0.0"
"1.9"
"8.2"
"9.3"
"4.5"
)
)
& out$(median$(1 5 3 2 4))
& out$(median$(1 5 3 6 4 2))
);
Output:
4.0999999999999996E+00 4.4500000000000002E+00 3.0000000000000000E+00 3.5000000000000000E+00
C
#include <stdio.h>
#include <stdlib.h>
typedef struct floatList {
float *list;
int size;
} *FloatList;
int floatcmp( const void *a, const void *b) {
if (*(const float *)a < *(const float *)b) return -1;
else return *(const float *)a > *(const float *)b;
}
float median( FloatList fl )
{
qsort( fl->list, fl->size, sizeof(float), floatcmp);
return 0.5 * ( fl->list[fl->size/2] + fl->list[(fl->size-1)/2]);
}
int main()
{
static float floats1[] = { 5.1, 2.6, 6.2, 8.8, 4.6, 4.1 };
static struct floatList flist1 = { floats1, sizeof(floats1)/sizeof(float) };
static float floats2[] = { 5.1, 2.6, 8.8, 4.6, 4.1 };
static struct floatList flist2 = { floats2, sizeof(floats2)/sizeof(float) };
printf("flist1 median is %7.2f\n", median(&flist1)); /* 4.85 */
printf("flist2 median is %7.2f\n", median(&flist2)); /* 4.60 */
return 0;
}
Quickselect algorithm
Average O(n) time:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define MAX_ELEMENTS 1000000
/* Return the k-th smallest item in array x of length len */
double quick_select(int k, double *x, int len)
{
inline void swap(int a, int b)
{
double t = x[a];
x[a] = x[b], x[b] = t;
}
int left = 0, right = len - 1;
int pos, i;
double pivot;
while (left < right)
{
pivot = x[k];
swap(k, right);
for (i = pos = left; i < right; i++)
{
if (x[i] < pivot)
{
swap(i, pos);
pos++;
}
}
swap(right, pos);
if (pos == k) break;
if (pos < k) left = pos + 1;
else right = pos - 1;
}
return x[k];
}
int main(void)
{
int i, length;
double *x, median;
/* Initialize random length double array with random doubles */
srandom(time(0));
length = random() % MAX_ELEMENTS;
x = malloc(sizeof(double) * length);
for (i = 0; i < length; i++)
{
// shifted by RAND_MAX for negative values
// divide by a random number for floating point
x[i] = (double)(random() - RAND_MAX / 2) / (random() + 1); // + 1 to not divide by 0
}
if (length % 2 == 0) // Even number of elements, median is average of middle two
{
median = (quick_select(length / 2, x, length) + quick_select(length / 2 - 1, x, length / 2)) / 2;
}
else // select middle element
{
median = quick_select(length / 2, x, length);
}
/* Sanity testing of median */
int less = 0, more = 0, eq = 0;
for (i = 0; i < length; i++)
{
if (x[i] < median) less ++;
else if (x[i] > median) more ++;
else eq ++;
}
printf("length: %d\nmedian: %lf\n<: %d\n>: %d\n=: %d\n", length, median, less, more, eq);
free(x);
return 0;
}
Output:
length: 992021
median: 0.000473
<: 496010
>: 496010
=: 1
C#
double median(double[] arr)
{
var sorted = arr.OrderBy(x => x).ToList();
var mid = arr.Length / 2;
return arr.Length % 2 == 0
? (sorted[mid] + sorted[mid-1]) / 2
: sorted[mid];
}
var write = (double[] x) =>
Console.WriteLine($"[{string.Join(", ", x)}]: {median(x)}");
write(new double[] { 1, 5, 3, 6, 4, 2 }); //even
write(new double[] { 1, 5, 3, 6, 4, 2, 7 }); //odd
write(new double[] { 5 }); //single
- Output:
[1, 5, 3, 6, 4, 2]: 3.5 [1, 5, 3, 6, 4, 2, 7]: 4 [5]: 5
C++
This function runs in linear time on average.
#include <algorithm>
// inputs must be random-access iterators of doubles
// Note: this function modifies the input range
template <typename Iterator>
double median(Iterator begin, Iterator end) {
// this is middle for odd-length, and "upper-middle" for even length
Iterator middle = begin + (end - begin) / 2;
// This function runs in O(n) on average, according to the standard
std::nth_element(begin, middle, end);
if ((end - begin) % 2 != 0) { // odd length
return *middle;
} else { // even length
// the "lower middle" is the max of the lower half
Iterator lower_middle = std::max_element(begin, middle);
return (*middle + *lower_middle) / 2.0;
}
}
#include <iostream>
int main() {
double a[] = {4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2};
double b[] = {4.1, 7.2, 1.7, 9.3, 4.4, 3.2};
std::cout << median(a+0, a + sizeof(a)/sizeof(a[0])) << std::endl; // 4.4
std::cout << median(b+0, b + sizeof(b)/sizeof(b[0])) << std::endl; // 4.25
return 0;
}
Order Statistic Tree
Uses a GNU C++ policy-based data structure to compute median in O(log n) time.
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
// the std::less_equal<> comparator allows the tree to support duplicates
typedef __gnu_pbds::tree<double, __gnu_pbds::null_type, std::less_equal<double>, __gnu_pbds::rb_tree_tag, __gnu_pbds::tree_order_statistics_node_update> ost_t;
// The lookup method, find_by_order (aka Select), is O(log n) for this data structure, much faster than std::nth_element()
double median(ost_t &OST)
{
int n = OST.size();
int m = n/2;
if (n == 1)
return *OST.find_by_order(0);
if (n == 2)
return (*OST.find_by_order(0) + *OST.find_by_order(1)) / 2;
if (n & 1) // odd number of elements
return *OST.find_by_order(m);
else // even number of elements
return (*OST.find_by_order(m) + *OST.find_by_order(m-1)) / 2;
}
int main(int argc, char* argv[])
{
ost_t ostree;
// insertion is also O(log n) for OSTs
ostree.insert(4.1);
ostree.insert(7.2);
ostree.insert(1.7);
ostree.insert(9.3);
ostree.insert(4.4);
ostree.insert(3.2);
printf("%.3f\n", median(ostree)); // 4.250
return 0;
}
Clojure
Simple:
(defn median [ns]
(let [ns (sort ns)
cnt (count ns)
mid (bit-shift-right cnt 1)]
(if (odd? cnt)
(nth ns mid)
(/ (+ (nth ns mid) (nth ns (dec mid))) 2))))
COBOL
Intrinsic function:
FUNCTION MEDIAN(some-table (ALL))
Common Lisp
The recursive partitioning solution, without the median of medians optimization.
((defun select-nth (n list predicate)
"Select nth element in list, ordered by predicate, modifying list."
(do ((pivot (pop list))
(ln 0) (left '())
(rn 0) (right '()))
((endp list)
(cond
((< n ln) (select-nth n left predicate))
((eql n ln) pivot)
((< n (+ ln rn 1)) (select-nth (- n ln 1) right predicate))
(t (error "n out of range."))))
(if (funcall predicate (first list) pivot)
(psetf list (cdr list)
(cdr list) left
left list
ln (1+ ln))
(psetf list (cdr list)
(cdr list) right
right list
rn (1+ rn)))))
(defun median (list predicate)
(select-nth (floor (length list) 2) list predicate))
Craft Basic
define limit = 10, iterations = 6
define iteration, size, middle, plusone
define point, top, high, low, pivot
dim list[limit]
dim stack[limit]
for iteration = 1 to iterations
gosub fill
gosub median
next iteration
end
sub fill
print "list: ",
erasearray list
let size = int(rnd * limit) + 1
if size <= 2 then
let size = 3
endif
for i = 0 to size - 1
let list[i] = rnd * 1000 + rnd
print list[i],
gosub printcomma
next i
return
sub median
gosub sort
print newline, "size: ", size, tab,
let middle = int((size - 1)/ 2)
print "middle: ", middle + 1, tab,
if size mod 2 then
print "median: ", list[middle]
else
let plusone = middle + 1
print "median: ", (list[middle] + list[plusone]) / 2
endif
print
return
sub sort
let low = 0
let high = size - 1
let top = -1
let top = top + 1
let stack[top] = low
let top = top + 1
let stack[top] = high
do
if top < 0 then
break
endif
let high = stack[top]
let top = top - 1
let low = stack[top]
let top = top - 1
let i = low - 1
for j = low to high - 1
if list[j] <= list[high] then
let i = i + 1
let t = list[i]
let list[i] = list[j]
let list[j] = t
endif
next j
let point = i + 1
let t = list[point]
let list[point] = list[high]
let list[high] = t
let pivot = i + 1
if pivot - 1 > low then
let top = top + 1
let stack[top] = low
let top = top + 1
let stack[top] = pivot - 1
endif
if pivot + 1 < high then
let top = top + 1
let stack[top] = pivot + 1
let top = top + 1
let stack[top] = high
endif
wait
loop top >= 0
print newline, "sorted: ",
for i = 0 to size - 1
print list[i],
gosub printcomma
next i
return
sub printcomma
if i < size - 1 then
print comma, " ",
endif
return
- Output:
list: 290.66, 870.46, 880.86 sorted: 290.66, 870.46, 880.86 size: 3 middle: 2 median: 870.46 list: 910.91, 50.79, 790.58, 960.61 sorted: 50.79, 790.58, 910.91, 960.61 size: 4 middle: 2 median: 850.74 list: 570.31, 500.16, 490.97, 370.48, 240.18, 880.23, 190.61, 950.19 sorted: 190.61, 240.18, 370.48, 490.97, 500.16, 570.31, 880.23, 950.19 size: 8 middle: 4 median: 495.57 list: 120.87, 570.87, 570.85, 800.27, 200.04, 250.09, 870.04, 200.58, 800.61 sorted: 120.87, 200.04, 200.58, 250.09, 570.85, 570.87, 800.27, 800.61, 870.04 size: 9 middle: 5 median: 570.85 list: 810.33, 760.55, 420.22, 730.64, 350.96 sorted: 350.96, 420.22, 730.64, 760.55, 810.33 size: 5 middle: 3 median: 730.64 list: 40.12, 860.77, 960.29, 920.13 sorted: 40.12, 860.77, 920.13, 960.29 size: 4 middle: 2 median: 890.45
Crystal
def median(ary)
srtd = ary.sort
alen = srtd.size
0.5*(srtd[(alen-1)//2] + srtd[alen//2])
end
a = [4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2]
puts median a
a = [4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2, 5.0]
puts median a
a = [5.0]
puts median a
- Output:
4.4 4.7 5.0
D
import std.stdio, std.algorithm;
T median(T)(T[] nums) pure nothrow {
nums.sort();
if (nums.length & 1)
return nums[$ / 2];
else
return (nums[$ / 2 - 1] + nums[$ / 2]) / 2.0;
}
void main() {
auto a1 = [5.1, 2.6, 6.2, 8.8, 4.6, 4.1];
writeln("Even median: ", a1.median);
auto a2 = [5.1, 2.6, 8.8, 4.6, 4.1];
writeln("Odd median: ", a2.median);
}
- Output:
Even median: 4.85 Odd median: 4.6
Delphi
program AveragesMedian;
{$APPTYPE CONSOLE}
uses Generics.Collections, Types;
function Median(aArray: TDoubleDynArray): Double;
var
lMiddleIndex: Integer;
begin
TArray.Sort<Double>(aArray);
lMiddleIndex := Length(aArray) div 2;
if Odd(Length(aArray)) then
Result := aArray[lMiddleIndex]
else
Result := (aArray[lMiddleIndex - 1] + aArray[lMiddleIndex]) / 2;
end;
begin
Writeln(Median(TDoubleDynArray.Create(4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2)));
Writeln(Median(TDoubleDynArray.Create(4.1, 7.2, 1.7, 9.3, 4.4, 3.2)));
end.
E
TODO: Use the selection algorithm, whatever that is
def median(list) {
def sorted := list.sort()
def count := sorted.size()
def mid1 := count // 2
def mid2 := (count - 1) // 2
if (mid1 == mid2) { # avoid inexact division
return sorted[mid1]
} else {
return (sorted[mid1] + sorted[mid2]) / 2
}
}
? median([1,9,2])
# value: 2
? median([1,9,2,4])
# value: 3.0
EasyLang
proc quickselect k . list[] res .
#
subr partition
mid = left
for i = left + 1 to right
if list[i] < list[left]
mid += 1
swap list[i] list[mid]
.
.
swap list[left] list[mid]
.
left = 1
right = len list[]
while left < right
partition
if mid < k
left = mid + 1
elif mid > k
right = mid - 1
else
left = right
.
.
res = list[k]
.
proc median . list[] res .
h = len list[] div 2 + 1
quickselect h list[] res
if len list[] mod 2 = 0
quickselect h - 1 list[] h
res = (res + h) / 2
.
.
test[] = [ 4.1 5.6 7.2 1.7 9.3 4.4 3.2 ]
median test[] med
print med
test[] = [ 4.1 7.2 1.7 9.3 4.4 3.2 ]
median test[] med
print med
4.40 4.25
EchoLisp
(define (median L) ;; O(n log(n))
(set! L (vector-sort! < (list->vector L)))
(define dim (// (vector-length L) 2))
(if (integer? dim)
(// (+ [L dim] [L (1- dim)]) 2)
[L (floor dim)]))
(median '( 3 4 5))
→ 4
(median '(6 5 4 3))
→ 4.5
(median (iota 10000))
→ 4999.5
(median (iota 10001))
→ 5000
Elena
ELENA 6.x :
import system'routines;
import system'math;
import extensions;
extension op
{
get Median()
{
var sorted := self.ascendant();
var len := sorted.Length;
if (len == 0)
{
^ nil
}
else
{
var middleIndex := len / 2;
if (len.mod(2) == 0)
{
^ (sorted[middleIndex - 1] + sorted[middleIndex]) / 2
}
else
{
^ sorted[middleIndex]
}
}
}
}
public program()
{
var a1 := new real[]{4.1r, 5.6r, 7.2r, 1.7r, 9.3r, 4.4r, 3.2r};
var a2 := new real[]{4.1r, 7.2r, 1.7r, 9.3r, 4.4r, 3.2r};
console.printLine("median of (",a1.asEnumerable(),") is ",a1.Median);
console.printLine("median of (",a2.asEnumerable(),") is ",a2.Median);
console.readChar()
}
- Output:
median of (4.1,5.6,7.2,1.7,9.3,4.4,3.2) is 4.4 median of (4.1,7.2,1.7,9.3,4.4,3.2) is 4.25
Elixir
defmodule Average do
def median([]), do: nil
def median(list) do
len = length(list)
sorted = Enum.sort(list)
mid = div(len, 2)
if rem(len,2) == 0, do: (Enum.at(sorted, mid-1) + Enum.at(sorted, mid)) / 2,
else: Enum.at(sorted, mid)
end
end
median = fn list -> IO.puts "#{inspect list} => #{inspect Average.median(list)}" end
median.([])
Enum.each(1..6, fn i ->
(for _ <- 1..i, do: :rand.uniform(6)) |> median.()
end)
- Output:
[] => nil [4] => 4 [1, 6] => 3.5 [5, 2, 4] => 4 [2, 3, 5, 1] => 2.5 [3, 2, 6, 3, 2] => 3 [6, 4, 2, 3, 1, 3] => 3.0
EMal
Sort
fun median = real by some real values
values = values.sort()
int mid = values.length / 2
return when(values.length % 2 == 0, (values[mid] + values[mid - 1]) / 2.0, values[mid])
end
writeLine(median(4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2, 5.0))
- Output:
4.7
Quickselect
fun median = real by some real values
fun swap = void by int a, int b
real t = values[a]
values[a] = values[b]
values[b] = t
end
fun select = real by int k
int left = 0
int right = values.length - 1
while left < right
real pivot = values[k]
swap(k, right)
int pos = left
for int i = left; i < right; i++
if values[i] < pivot
swap(i, pos)
++pos
end
end
swap(right, pos)
if pos == k do break
else if pos < k do left = pos + 1
else do right = pos - 1 end
end
return values[k]
end
int halfLength = values.length / 2
return when(values.length % 2 == 0,
(select(halfLength) + select(halfLength - 1)) / 2.0,
select(halfLength))
end
writeLine(median(4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2, 5.0))
- Output:
4.7
Erlang
-module(median).
-import(lists, [nth/2, sort/1]).
-compile(export_all).
test(MaxInt,ListSize,TimesToRun) ->
test(MaxInt,ListSize,TimesToRun,[[],[]]).
test(_,_,0,[GMAcc, OMAcc]) ->
Len = length(GMAcc),
{GMT,GMV} = lists:foldl(fun({T, V}, {AT,AV}) -> {AT + T, AV + V} end, {0,0}, GMAcc),
{OMT,OMV} = lists:foldl(fun({T, V}, {AT,AV}) -> {AT + T, AV + V} end, {0,0}, OMAcc),
io:format("QuickSelect Time: ~p, Val: ~p~nOriginal Time: ~p, Val: ~p~n", [GMT/Len, GMV/Len, OMT/Len, OMV/Len]);
test(M,N,T,[GMAcc, OMAcc]) ->
L = [rand:uniform(M) || _ <- lists:seq(1,N)],
GM = timer:tc(fun() -> qs_median(L) end),
OM = timer:tc(fun() -> median(L) end),
test(M,N,T-1,[[GM|GMAcc], [OM|OMAcc]]).
median(Unsorted) ->
Sorted = sort(Unsorted),
Length = length(Sorted),
Mid = Length div 2,
Rem = Length rem 2,
(nth(Mid+Rem, Sorted) + nth(Mid+1, Sorted)) / 2.
% ***********************************************************
% median based on quick select with optimizations for repeating numbers
% if it really matters it's a little faster
% by Roman Rabinovich
% ***********************************************************
qs_median([]) -> error;
qs_median([X]) -> X;
qs_median([P|_Tail] = List) ->
TargetPos = length(List)/2 + 0.5,
qs_median(List, TargetPos, P, 0).
qs_median([X], 1, _, 0) -> X;
qs_median([X], 1, _, Acc) -> (X + Acc)/2;
qs_median([P|Tail], TargetPos, LastP, Acc) ->
Smaller = [X || X <- Tail, X < P],
LS = length(Smaller),
qs_continue(P, LS, TargetPos, LastP, Smaller, Tail, Acc).
qs_continue(P, LS, TargetPos, _, _, _, 0) when LS + 1 == TargetPos -> P;
qs_continue(P, LS, TargetPos, _, _, _, Acc) when LS + 1 == TargetPos -> (P + Acc)/2;
qs_continue(P, 0, TargetPos, LastP, _SM, _TL, _Acc) when TargetPos == 0.5 ->
(P+LastP)/2;
qs_continue(P, LS, TargetPos, _LastP, SM, _TL, _Acc) when TargetPos == LS + 0.5 ->
qs_median(SM, TargetPos - 0.5, P, P);
qs_continue(P, LS, TargetPos, _LastP, SM, _TL, Acc) when LS + 1 > TargetPos ->
qs_median(SM, TargetPos, P, Acc);
qs_continue(P, LS, TargetPos, _LastP, _SM, TL, Acc) ->
Larger = [X || X <- TL, X >= P],
NewPos= TargetPos - LS -1,
case NewPos == 0.5 of
true ->
qs_median(Larger, 1, P, P);
false ->
qs_median(Larger, NewPos, P, Acc)
end.
ERRE
PROGRAM MEDIAN
DIM X[10]
PROCEDURE QUICK_SELECT
LT=0 RT=L-1
J=LT
REPEAT
PT=X[K]
SWAP(X[K],X[RT])
P=LT
FOR I=P TO RT-1 DO
IF X[I]<PT THEN SWAP(X[I],X[P]) P=P+1 END IF
END FOR
SWAP(X[RT],X[P])
IF P=K THEN EXIT PROCEDURE END IF
IF P<K THEN LT=P+1 END IF
IF P>=K THEN RT=P-1 END IF
UNTIL J>RT
END PROCEDURE
PROCEDURE MEDIAN
K=INT(L/2)
QUICK_SELECT
R=X[K]
IF L-2*INT(L/2)<>0 THEN R=(R+X[K+1])/2 END IF
END PROCEDURE
BEGIN
PRINT(CHR$(12);) !CLS
X[0]=4.4 X[1]=2.3 X[2]=-1.7 X[3]=7.5 X[4]=6.6 X[5]=0
X[6]=1.9 X[7]=8.2 X[8]=9.3 X[9]=4.5 X[10]=-11.7
L=11
MEDIAN
PRINT(R)
END PROGRAM
Ouput is 5.95
Euler Math Toolbox
The following function does much more than computing the median. It can handle a matrix of x values row by row. Then it can handle multiplicities in the vector v. Moreover it can search for the p median, not only the p=0.5 median.
>type median
function median (x, v: none, p)
## Default for v : none
## Default for p : 0.5
m=rows(x);
if m>1 then
y=zeros(m,1);
loop 1 to m;
y[#]=median(x[#],v,p);
end;
return y;
else
if v<>none then
{xs,i}=sort(x); vsh=v[i];
n=cols(xs);
ns=sum(vsh);
i=1+p*(ns-1); i0=floor(i);
vs=cumsum(vsh);
loop 1 to n
if vs[#]>i0 then
return xs[#];
elseif vs[#]+1>i0 then
k=#+1;
repeat;
if vsh[k]>0 or k>n then break; endif;
k=k+1;
end;
return (1-(i-i0))*xs[#]+(i-i0)*xs[k]+0;
endif;
end;
return xs[n];
else
xs=sort(x);
n=cols(x);
i=1+p*(n-1); i0=floor(i);
if i0==n then return xs[n]; endif;
return (i-i0)*xs[i+1]+(1-(i-i0))*xs[i];
endif;
endif;
endfunction
>median(1:10)
5.5
>median(1:9)
5
>median(1:10,p=0.2)
2.8
>0.2*10+0.8*1
2.8
Euphoria
function median(sequence s)
atom min,k
-- Selection sort of half+1
for i = 1 to length(s)/2+1 do
min = s[i]
k = 0
for j = i+1 to length(s) do
if s[j] < min then
min = s[j]
k = j
end if
end for
if k then
s[k] = s[i]
s[i] = min
end if
end for
if remainder(length(s),2) = 0 then
return (s[$/2]+s[$/2+1])/2
else
return s[$/2+1]
end if
end function
? median({ 4.4, 2.3, -1.7, 7.5, 6.6, 0.0, 1.9, 8.2, 9.3, 4.5 })
Output:
4.45
Excel
Assuming the values are entered in the A column, type into any cell which will not be part of the list :
=MEDIAN(A1:A10)
Assuming 10 values will be entered, alternatively, you can just type
=MEDIAN(
and then select the start and end cells, not necessarily in the same row or column.
The output for the first expression, for any 10 numbers is
23 11,5
21
12
3
19
7
23
11
9
0
F#
Median of Medians algorithm implementation
let rec splitToFives list =
match list with
| a::b::c::d::e::tail ->
([a;b;c;d;e])::(splitToFives tail)
| [] -> []
| _ ->
let left = 5 - List.length (list)
let last = List.append list (List.init left (fun _ -> System.Double.PositiveInfinity) )
in [last]
let medianFromFives =
List.map ( fun (i:float list) ->
List.nth (List.sort i) 2 )
let start l =
let rec magicFives list k =
if List.length(list) <= 10 then
List.nth (List.sort list) (k-1)
else
let s = splitToFives list
let M = medianFromFives s
let m = magicFives M (int(System.Math.Ceiling((float(List.length M))/2.)))
let (ll,lg) = List.partition ( fun i -> i < m ) list
let (le,lg) = List.partition ( fun i -> i = m ) lg
in
if (List.length ll >= k) then
magicFives ll k
else if (List.length ll + List.length le >= k ) then m
else
magicFives lg (k-(List.length ll)-(List.length le))
in
let len = List.length l in
if (len % 2 = 1) then
magicFives l ((len+1)/2)
else
let a = magicFives l (len/2)
let b = magicFives l ((len/2)+1)
in (a+b)/2.
let z = [1.;5.;2.;8.;7.;2.]
start z
let z' = [1.;5.;2.;8.;7.]
start z'
Factor
The quicksort-style solution, with random pivoting. Takes the lesser of the two medians for even sequences.
USING: arrays kernel locals math math.functions random sequences ;
IN: median
: pivot ( seq -- pivot ) random ;
: split ( seq pivot -- {lt,eq,gt} )
[ [ < ] curry partition ] keep
[ = ] curry partition
3array ;
DEFER: nth-in-order
:: nth-in-order-recur ( seq ind -- elt )
seq dup pivot split
dup [ length ] map 0 [ + ] accumulate nip
dup [ ind <= [ 1 ] [ 0 ] if ] map sum 1 -
[ swap nth ] curry bi@
ind swap -
nth-in-order ;
: nth-in-order ( seq ind -- elt )
dup 0 =
[ drop first ]
[ nth-in-order-recur ]
if ;
: median ( seq -- median )
dup length 1 - 2 / floor nth-in-order ;
Usage:
( scratchpad ) 11 iota median .
5
( scratchpad ) 10 iota median .
4
Forth
This uses the O(n) algorithm derived from quicksort.
-1 cells constant -cell
: cell- -cell + ;
defer lessthan ( a@ b@ -- ? ) ' < is lessthan
: mid ( l r -- mid ) over - 2/ -cell and + ;
: exch ( addr1 addr2 -- ) dup @ >r over @ swap ! r> swap ! ;
: part ( l r -- l r r2 l2 )
2dup mid @ >r ( r: pivot )
2dup begin
swap begin dup @ r@ lessthan while cell+ repeat
swap begin r@ over @ lessthan while cell- repeat
2dup <= if 2dup exch >r cell+ r> cell- then
2dup > until r> drop ;
0 value midpoint
: select ( l r -- )
begin 2dup < while
part
dup midpoint >= if nip nip ( l l2 ) else
over midpoint <= if drop rot drop swap ( r2 r ) else
2drop 2drop exit then then
repeat 2drop ;
: median ( array len -- m )
1- cells over + 2dup mid to midpoint
select midpoint @ ;
create test 4 , 2 , 1 , 3 , 5 ,
test 4 median . \ 2
test 5 median . \ 3
Fortran
program Median_Test
real :: a(7) = (/ 4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2 /), &
b(6) = (/ 4.1, 7.2, 1.7, 9.3, 4.4, 3.2 /)
print *, median(a)
print *, median(b)
contains
function median(a, found)
real, dimension(:), intent(in) :: a
! the optional found argument can be used to check
! if the function returned a valid value; we need this
! just if we suspect our "vector" can be "empty"
logical, optional, intent(out) :: found
real :: median
integer :: l
real, dimension(size(a,1)) :: ac
if ( size(a,1) < 1 ) then
if ( present(found) ) found = .false.
else
ac = a
! this is not an intrinsic: peek a sort algo from
! Category:Sorting, fixing it to work with real if
! it uses integer instead.
call sort(ac)
l = size(a,1)
if ( mod(l, 2) == 0 ) then
median = (ac(l/2+1) + ac(l/2))/2.0
else
median = ac(l/2+1)
end if
if ( present(found) ) found = .true.
end if
end function median
end program Median_Test
If one refers to Quickselect_algorithm#Fortran which offers function FINDELEMENT(K,A,N) that returns the value of A(K) when the array of N elements has been rearranged if necessary so that A(K) is the K'th in order, then, supposing that a version is devised using the appropriate type for array A,
K = N/2
MEDIAN = FINDELEMENT(K + 1,A,N)
IF (MOD(N,2).EQ.0) MEDIAN = (FINDELEMENT(K,A,N) + MEDIAN)/2
As well as returning a result, the function possibly re-arranges the elements of the array, which is not "pure" behaviour. Not to the degree of fully sorting them, merely that all elements before K are not larger than A(K) as it now is, and all elements after K are not smaller than A(K).
FreeBASIC
' FB 1.05.0 Win64
Sub quicksort(a() As Double, first As Integer, last As Integer)
Dim As Integer length = last - first + 1
If length < 2 Then Return
Dim pivot As Double = a(first + length\ 2)
Dim lft As Integer = first
Dim rgt As Integer = last
While lft <= rgt
While a(lft) < pivot
lft +=1
Wend
While a(rgt) > pivot
rgt -= 1
Wend
If lft <= rgt Then
Swap a(lft), a(rgt)
lft += 1
rgt -= 1
End If
Wend
quicksort(a(), first, rgt)
quicksort(a(), lft, last)
End Sub
Function median(a() As Double) As Double
Dim lb As Integer = LBound(a)
Dim ub As Integer = UBound(a)
Dim length As Integer = ub - lb + 1
If length = 0 Then Return 0.0/0.0 '' NaN
If length = 1 Then Return a(ub)
Dim mb As Integer = (lb + ub) \2
If length Mod 2 = 1 Then Return a(mb)
Return (a(mb) + a(mb + 1))/2.0
End Function
Dim a(0 To 9) As Double = {4.4, 2.3, -1.7, 7.5, 6.6, 0.0, 1.9, 8.2, 9.3, 4.5}
quicksort(a(), 0, 9)
Print "Median for all 10 elements : "; median(a())
' now get rid of final element
Dim b(0 To 8) As Double = {4.4, 2.3, -1.7, 7.5, 6.6, 0.0, 1.9, 8.2, 9.3}
quicksort(b(), 0, 8)
Print "Median for first 9 elements : "; median(b())
Print
Print "Press any key to quit"
Sleep
- Output:
Median for all 10 elements : 4.45 Median for first 9 elements : 4.4
FutureBasic
FB has native averaging functions.
local fn MedianAverage( arguments as CFArrayRef ) as CFStringRef
ExpressionRef expRef = fn ExpressionForFunction( @"median:", @[fn ExpressionForConstantValue( arguments )] )
CFNumberRef result = fn ExpressionValueWithObject( expRef, NULL, NULL )
CFStringRef median = fn NumberStringValue( result )
end fn = median
print fn MedianAverage( @[@1, @9, @2] ) // 2
print fn MedianAverage( @[@1, @9, @2, @4] ) // 3
print fn MedianAverage( @[@5.961475, @2.025856, @7.262835, @1.814272, @2.281911, @4.854716] ) // 3.5683135
print fn MedianAverage( @[@4.1, @5.6, @7.2, @1.7, @9.3, @4.4, @3.2] ) // 4.4
print fn MedianAverage( @[@40.12, @860.77, @960.29, @920.13] ) // 890.45
HandleEvents
- Output:
2 3 3.5683135 4.4 890.45
GAP
Median := function(v)
local n, w;
w := SortedList(v);
n := Length(v);
return (w[QuoInt(n + 1, 2)] + w[QuoInt(n, 2) + 1]) / 2;
end;
a := [41, 56, 72, 17, 93, 44, 32];
b := [41, 72, 17, 93, 44, 32];
Median(a);
# 44
Median(b);
# 85/2
Go
Sort
Go built-in sort. O(n log n).
package main
import (
"fmt"
"sort"
)
func main() {
fmt.Println(median([]float64{3, 1, 4, 1})) // prints 2
fmt.Println(median([]float64{3, 1, 4, 1, 5})) // prints 3
}
func median(a []float64) float64 {
sort.Float64s(a)
half := len(a) / 2
m := a[half]
if len(a)%2 == 0 {
m = (m + a[half-1]) / 2
}
return m
}
Partial selection sort
The task description references the WP entry for "selection algorithm" which (as of this writing) gives just one pseudocode example, which is implemented here. As the WP article notes, it is O(kn). Unfortunately in the case of median, k is n/2 so the algorithm is O(n^2). Still, it gives the idea of median by selection. Note that the partial selection sort does leave the k smallest values sorted, so in the case of an even number of elements, the two elements to average are available after a single call to sel().
package main
import "fmt"
func main() {
fmt.Println(median([]float64{3, 1, 4, 1})) // prints 2
fmt.Println(median([]float64{3, 1, 4, 1, 5})) // prints 3
}
func median(a []float64) float64 {
half := len(a) / 2
med := sel(a, half)
if len(a)%2 == 0 {
return (med + a[half-1]) / 2
}
return med
}
func sel(list []float64, k int) float64 {
for i, minValue := range list[:k+1] {
minIndex := i
for j := i + 1; j < len(list); j++ {
if list[j] < minValue {
minIndex = j
minValue = list[j]
list[i], list[minIndex] = minValue, list[i]
}
}
}
return list[k]
}
Quickselect
It doesn't take too much more code to implement a quickselect with random pivoting, which should run in expected time O(n). The qsel function here permutes elements of its parameter "a" in place. It leaves the slice somewhat more ordered, but unlike the sort and partial sort examples above, does not guarantee that element k-1 is in place. For the case of an even number of elements then, median must make two separate qsel() calls.
package main
import (
"fmt"
"math/rand"
)
func main() {
fmt.Println(median([]float64{3, 1, 4, 1})) // prints 2
fmt.Println(median([]float64{3, 1, 4, 1, 5})) // prints 3
}
func median(list []float64) float64 {
half := len(list) / 2
med := qsel(list, half)
if len(list)%2 == 0 {
return (med + qsel(list, half-1)) / 2
}
return med
}
func qsel(a []float64, k int) float64 {
for len(a) > 1 {
px := rand.Intn(len(a))
pv := a[px]
last := len(a) - 1
a[px], a[last] = a[last], pv
px = 0
for i, v := range a[:last] {
if v < pv {
a[px], a[i] = v, a[px]
px++
}
}
if px == k {
return pv
}
if k < px {
a = a[:px]
} else {
// swap elements. simply assigning a[last] would be enough to
// allow qsel to return the correct result but it would leave slice
// "a" unusable for subsequent use. we want this full swap so that
// we can make two successive qsel calls in the case of median
// of an even number of elements.
a[px], a[last] = pv, a[px]
a = a[px+1:]
k -= px + 1
}
}
return a[0]
}
Groovy
Solution (brute force sorting, with arithmetic averaging of dual midpoints (even sizes)):
def median(Iterable col) {
def s = col as SortedSet
if (s == null) return null
if (s.empty) return 0
def n = s.size()
def m = n.intdiv(2)
def l = s.collect { it }
n%2 == 1 ? l[m] : (l[m] + l[m-1])/2
}
Test:
def a = [4.4, 2.3, -1.7, 7.5, 6.6, 0.0, 1.9, 8.2, 9.3, 4.5]
def sz = a.size()
(0..sz).each {
println """${median(a[0..<(sz-it)])} == median(${a[0..<(sz-it)]})
${median(a[it..<sz])} == median(${a[it..<sz]})"""
}
Output:
4.45 == median([4.4, 2.3, -1.7, 7.5, 6.6, 0.0, 1.9, 8.2, 9.3, 4.5]) 4.45 == median([4.4, 2.3, -1.7, 7.5, 6.6, 0.0, 1.9, 8.2, 9.3, 4.5]) 4.4 == median([4.4, 2.3, -1.7, 7.5, 6.6, 0.0, 1.9, 8.2, 9.3]) 4.5 == median([2.3, -1.7, 7.5, 6.6, 0.0, 1.9, 8.2, 9.3, 4.5]) 3.35 == median([4.4, 2.3, -1.7, 7.5, 6.6, 0.0, 1.9, 8.2]) 5.55 == median([-1.7, 7.5, 6.6, 0.0, 1.9, 8.2, 9.3, 4.5]) 2.3 == median([4.4, 2.3, -1.7, 7.5, 6.6, 0.0, 1.9]) 6.6 == median([7.5, 6.6, 0.0, 1.9, 8.2, 9.3, 4.5]) 3.35 == median([4.4, 2.3, -1.7, 7.5, 6.6, 0.0]) 5.55 == median([6.6, 0.0, 1.9, 8.2, 9.3, 4.5]) 4.4 == median([4.4, 2.3, -1.7, 7.5, 6.6]) 4.5 == median([0.0, 1.9, 8.2, 9.3, 4.5]) 3.35 == median([4.4, 2.3, -1.7, 7.5]) 6.35 == median([1.9, 8.2, 9.3, 4.5]) 2.3 == median([4.4, 2.3, -1.7]) 8.2 == median([8.2, 9.3, 4.5]) 3.35 == median([4.4, 2.3]) 6.9 == median([9.3, 4.5]) 4.4 == median([4.4]) 4.5 == median([4.5]) 0 == median([]) 0 == median([])
Haskell
This uses a quick select algorithm and runs in expected O(n) time.
import Data.List (partition)
nth :: Ord t => [t] -> Int -> t
nth (x:xs) n
| k == n = x
| k > n = nth ys n
| otherwise = nth zs $ n - k - 1
where
(ys, zs) = partition (< x) xs
k = length ys
medianMay :: (Fractional a, Ord a) => [a] -> Maybe a
medianMay xs
| n < 1 = Nothing
| even n = Just ((nth xs (div n 2) + nth xs (div n 2 - 1)) / 2.0)
| otherwise = Just (nth xs (div n 2))
where
n = length xs
main :: IO ()
main =
mapM_
(printMay . medianMay)
[[], [7], [5, 3, 4], [5, 4, 2, 3], [3, 4, 1, -8.4, 7.2, 4, 1, 1.2]]
where
printMay = maybe (putStrLn "(not defined)") print
- Output:
(not defined) 7.0 4.0 3.5 2.1
Or
> Math.Statistics.median [1,9,2,4]
3.0
HicEst
If the input has an even number of elements, median is the mean of the middle two values:
REAL :: n=10, vec(n)
vec = RAN(1)
SORT(Vector=vec, Sorted=vec) ! in-place Merge-Sort
IF( MOD(n,2) ) THEN ! odd n
median = vec( CEILING(n/2) )
ELSE
median = ( vec(n/2) + vec(n/2 + 1) ) / 2
ENDIF
Icon and Unicon
A quick and dirty solution:
procedure main(args)
write(median(args))
end
procedure median(A)
A := sort(A)
n := *A
return if n % 2 = 1 then A[n/2+1]
else (A[n/2]+A[n/2+1])/2.0 | 0 # 0 if empty list
end
Sample outputs:
->am 3 1 4 1 5 9 7 6 3 4 ->am 3 1 4 1 5 9 7 6 4.5 ->
J
The verb median
is available from the stats/base
addon and returns the mean of the two middle values for an even number of elements:
require 'stats/base'
median 1 9 2 4
3
The definition given in the addon script is:
midpt=: -:@<:@#
median=: -:@(+/)@((<. , >.)@midpt { /:~)
If, for an even number of elements, both values were desired when those two values are distinct, then the following implementation would suffice:
median=: ~.@(<. , >.)@midpt { /:~
median 1 9 2 4
2 4
Java
Sorting:
double median(List<Double> values) {
/* copy, as to prevent modifying 'values' */
List<Double> list = new ArrayList<>(values);
Collections.sort(list);
/* 'mid' will be truncated */
int mid = list.size() / 2;
return switch (list.size() % 2) {
case 0 -> {
double valueA = list.get(mid);
double valueB = list.get(mid + 1);
yield (valueA + valueB) / 2;
}
case 1 -> list.get(mid);
default -> 0;
};
}
Using priority queue (which sorts under the hood):
public static double median2(List<Double> list) {
PriorityQueue<Double> pq = new PriorityQueue<Double>(list);
int n = list.size();
for (int i = 0; i < (n - 1) / 2; i++)
pq.poll(); // discard first half
if (n % 2 != 0) // odd length
return pq.poll();
else
return (pq.poll() + pq.poll()) / 2.0;
}
This version operates on objects rather than primitives and uses abstractions to operate on all of the standard numerics.
@FunctionalInterface
interface MedianFinder<T, R> extends Function<Collection<T>, R> {
@Override
R apply(Collection<T> data);
}
class MedianFinderImpl<T, R> implements MedianFinder<T, R> {
private final Supplier<R> ifEmpty;
private final Function<T, R> ifOdd;
private final Function<List<T>, R> ifEven;
MedianFinderImpl(Supplier<R> ifEmpty, Function<T, R> ifOdd, Function<List<T>, R> ifEven) {
this.ifEmpty = ifEmpty;
this.ifOdd = ifOdd;
this.ifEven = ifEven;
}
@Override
public R apply(Collection<T> data) {
return Objects.requireNonNull(data, "data must not be null").isEmpty()
? ifEmpty.get()
: (data.size() & 1) == 0
? ifEven.apply(data.stream().sorted()
.skip(data.size() / 2 - 1)
.limit(2).toList())
: ifOdd.apply(data.stream().sorted()
.skip(data.size() / 2)
.limit(1).findFirst().get());
}
}
public class MedianOf {
private static final MedianFinder<Integer, Integer> INTEGERS = new MedianFinderImpl<>(() -> 0, n -> n, pair -> (pair.get(0) + pair.get(1)) / 2);
private static final MedianFinder<Integer, Float> INTEGERS_AS_FLOAT = new MedianFinderImpl<>(() -> 0f, n -> n * 1f, pair -> (pair.get(0) + pair.get(1)) / 2f);
private static final MedianFinder<Integer, Double> INTEGERS_AS_DOUBLE = new MedianFinderImpl<>(() -> 0d, n -> n * 1d, pair -> (pair.get(0) + pair.get(1)) / 2d);
private static final MedianFinder<Float, Float> FLOATS = new MedianFinderImpl<>(() -> 0f, n -> n, pair -> (pair.get(0) + pair.get(1)) / 2);
private static final MedianFinder<Double, Double> DOUBLES = new MedianFinderImpl<>(() -> 0d, n -> n, pair -> (pair.get(0) + pair.get(1)) / 2);
private static final MedianFinder<BigInteger, BigInteger> BIG_INTEGERS = new MedianFinderImpl<>(() -> BigInteger.ZERO, n -> n, pair -> pair.get(0).add(pair.get(1)).divide(BigInteger.TWO));
private static final MedianFinder<BigInteger, BigDecimal> BIG_INTEGERS_AS_BIG_DECIMAL = new MedianFinderImpl<>(() -> BigDecimal.ZERO, BigDecimal::new, pair -> new BigDecimal(pair.get(0).add(pair.get(1))).divide(BigDecimal.valueOf(2), RoundingMode.FLOOR));
private static final MedianFinder<BigDecimal, BigDecimal> BIG_DECIMALS = new MedianFinderImpl<>(() -> BigDecimal.ZERO, n -> n, pair -> pair.get(0).add(pair.get(1)).divide(BigDecimal.valueOf(2), RoundingMode.FLOOR));
public static Integer integers(Collection<Integer> integerCollection) { return INTEGERS.apply(integerCollection); }
public static Float integersAsFloat(Collection<Integer> integerCollection) { return INTEGERS_AS_FLOAT.apply(integerCollection); }
public static Double integersAsDouble(Collection<Integer> integerCollection) { return INTEGERS_AS_DOUBLE.apply(integerCollection); }
public static Float floats(Collection<Float> floatCollection) { return FLOATS.apply(floatCollection); }
public static Double doubles(Collection<Double> doubleCollection) { return DOUBLES.apply(doubleCollection); }
public static BigInteger bigIntegers(Collection<BigInteger> bigIntegerCollection) { return BIG_INTEGERS.apply(bigIntegerCollection); }
public static BigDecimal bigIntegersAsBigDecimal(Collection<BigInteger> bigIntegerCollection) { return BIG_INTEGERS_AS_BIG_DECIMAL.apply(bigIntegerCollection); }
public static BigDecimal bigDecimals(Collection<BigDecimal> bigDecimalCollection) { return BIG_DECIMALS.apply(bigDecimalCollection); }
}
JavaScript
ES5
function median(ary) {
if (ary.length == 0)
return null;
ary.sort(function (a,b){return a - b})
var mid = Math.floor(ary.length / 2);
if ((ary.length % 2) == 1) // length is odd
return ary[mid];
else
return (ary[mid - 1] + ary[mid]) / 2;
}
median([]); // null
median([5,3,4]); // 4
median([5,4,2,3]); // 3.5
median([3,4,1,-8.4,7.2,4,1,1.2]); // 2.1
ES6
Using a quick select algorithm
(() => {
'use strict';
// median :: [Num] -> Num
function median(xs) {
// nth :: [Num] -> Int -> Maybe Num
let nth = (xxs, n) => {
if (xxs.length > 0) {
let [x, xs] = uncons(xxs),
[ys, zs] = partition(y => y < x, xs),
k = ys.length;
return k === n ? x : (
k > n ? nth(ys, n) : nth(zs, n - k - 1)
);
} else return undefined;
},
n = xs.length;
return even(n) ? (
(nth(xs, div(n, 2)) + nth(xs, div(n, 2) - 1)) / 2
) : nth(xs, div(n, 2));
}
// GENERIC
// partition :: (a -> Bool) -> [a] -> ([a], [a])
let partition = (p, xs) =>
xs.reduce((a, x) =>
p(x) ? [a[0].concat(x), a[1]] : [a[0], a[1].concat(x)], [
[],
[]
]),
// uncons :: [a] -> Maybe (a, [a])
uncons = xs => xs.length ? [xs[0], xs.slice(1)] : undefined,
// even :: Integral a => a -> Bool
even = n => n % 2 === 0,
// div :: Num -> Num -> Int
div = (x, y) => Math.floor(x / y);
return [
[],
[5, 3, 4],
[5, 4, 2, 3],
[3, 4, 1, -8.4, 7.2, 4, 1, 1.2]
].map(median);
})();
- Output:
[
null,
4,
3.5,
2.1
]
jq
def median:
length as $length
| sort as $s
| if $length == 0 then null
else ($length / 2 | floor) as $l2
| if ($length % 2) == 0 then
($s[$l2 - 1] + $s[$l2]) / 2
else $s[$l2]
end
end ;
This definition can be used in a jq program, but to illustrate how it can be used as a command line filter, suppose the definition and the program median are in a file named median.jq, and that the file in.dat contains a sequence of arrays, such as
[4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2]
[4.1, 7.2, 1.7, 9.3, 4.4, 3.2]
Then invoking the jq program yields a stream of values:
$ jq -f median.jq in.dat
4.4
4.25
Julia
Julia has a built-in median() function
using Statistics
function median2(n)
s = sort(n)
len = length(n)
if len % 2 == 0
return (s[floor(Int, len / 2) + 1] + s[floor(Int, len / 2)]) / 2
else
return s[floor(Int, len / 2) + 1]
end
end
a = [4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2]
b = [4.1, 7.2, 1.7, 9.3, 4.4, 3.2]
@show a b median2(a) median(a) median2(b) median(b)
- Output:
a = [4.1,5.6,7.2,1.7,9.3,4.4,3.2] b = [4.1,7.2,1.7,9.3,4.4,3.2] median2(a) = 4.4 median(a) = 4.4 median2(b) = 4.25 median(b) = 4.25
K
med:{a:x@<x; i:(#a)%2; :[(#a)!2; a@i; {(+/x)%#x} a@i,i-1]}
v:10*6 _draw 0
v
5.961475 2.025856 7.262835 1.814272 2.281911 4.854716
med[v]
3.568313
med[1_ v]
2.281911
An alternate solution which works in the oK implementation using the same dataset v from above and shows both numbers around the median point on even length datasets would be:
med:{a:x@<x; i:_(#a)%2
$[2!#a; a@i; |a@i,i-1]}
med[v]
2.2819 4.8547
Kotlin
fun median(l: List<Double>) = l.sorted().let { (it[it.size / 2] + it[(it.size - 1) / 2]) / 2 }
fun main(args: Array<String>) {
median(listOf(5.0, 3.0, 4.0)).let { println(it) } // 4
median(listOf(5.0, 4.0, 2.0, 3.0)).let { println(it) } // 3.5
median(listOf(3.0, 4.0, 1.0, -8.4, 7.2, 4.0, 1.0, 1.2)).let { println(it) } // 2.1
}
Lambdatalk
{def median
{lambda {:s}
{let { {:a {A.sort! < {A.new :s}}}
{:len {S.length :s}}
} {* 0.5 {+ {A.get {floor {/ {- :len 1} 2}} :a}
{A.get {floor {/ :len 2}} :a} }} }}}
-> median
{median 4.1 5.6 7.2 1.7 9.3 4.4 3.2}
-> 4.4
{median 4.1 7.2 1.7 9.3 4.4 3.2}
-> 4.25
Lasso
can't use Lasso's built in median method because that takes 3 values, not an array of indeterminate length
Lasso's built in function is "median( value_1, value_2, value_3 )"
define median_ext(a::array) => {
#a->sort
if(#a->size % 2) => {
// odd numbered element array, pick middle
return #a->get(#a->size / 2 + 1)
else
// even number elements in array
return (#a->get(#a->size / 2) + #a->get(#a->size / 2 + 1)) / 2.0
}
}
median_ext(array(3,2,7,6)) // 4.5
median_ext(array(3,2,9,7,6)) // 6
Liberty BASIC
dim a( 100), b( 100) ' assumes we will not have vectors of more terms...
a$ ="4.1,5.6,7.2,1.7,9.3,4.4,3.2"
print "Median is "; median( a$) ' 4.4 7 terms
print
a$ ="4.1,7.2,1.7,9.3,4.4,3.2"
print "Median is "; median( a$) ' 4.25 6 terms
print
a$ ="4.1,4,1.2,6.235,7868.33" ' 4.1
print "Median of "; a$; " is "; median( a$)
print
a$ ="1,5,3,2,4" ' 3
print "Median of "; a$; " is "; median( a$)
print
a$ ="1,5,3,6,4,2" ' 3.5
print "Median of "; a$; " is "; median( a$)
print
a$ ="4.4,2.3,-1.7,7.5,6.6,0.0,1.9,8.2,9.3,4.5" ' 4.45
print "Median of "; a$; " is "; median( a$)
end
function median( a$)
i =1
do
v$ =word$( a$, i, ",")
if v$ ="" then exit do
print v$,
a( i) =val( v$)
i =i +1
loop until 0
print
sort a(), 1, i -1
for j =1 to i -1
print a( j),
next j
print
middle =( i -1) /2
intmiddle =int( middle)
if middle <>intmiddle then median= a( 1 +intmiddle) else median =( a( intmiddle) +a( intmiddle +1)) /2
end function
4.1 5.6 7.2 1.7 9.3 4.4 3.2 Median is 4.4 4.1 7.2 1.7 9.3 4.4 3.2 Median is 4.25 4.1 4 1.2 6.235 7868.33 Median of 4.1,4,1.2,6.235,7868.33 is 4.1 1 5 3 2 4 Median of 1,5,3,2,4 is 3 1 5 3 6 4 2 Median of 1,5,3,6,4,2 is 3.5 4.4 2.3 -1.7 7.5 6.6 0.0 1.9 8.2 9.3 4.5 Median of 4.4,2.3,-1.7,7.5,6.6,0.0,1.9,8.2,9.3,4.5 is 4.45
Lingo
on median (numlist)
-- numlist = numlist.duplicate() -- if input list should not be altered
numlist.sort()
if numlist.count mod 2 then
return numlist[numlist.count/2+1]
else
return (numlist[numlist.count/2]+numlist[numlist.count/2+1])/2.0
end if
end
LiveCode
LC has median as a built-in function
put median("4.1,5.6,7.2,1.7,9.3,4.4,3.2") & "," & median("4.1,7.2,1.7,9.3,4.4,3.2")
returns 4.4, 4.25
To make our own, we need own own floor function first
function floor n
if n < 0 then
return (trunc(n) - 1)
else
return trunc(n)
end if
end floor
function median2 x
local n, m
set itemdelimiter to comma
sort items of x ascending numeric
put the number of items of x into n
put floor(n / 2) into m
if n mod 2 is 0 then
return (item m of x + item (m + 1) of x) / 2
else
return item (m + 1) of x
end if
end median2
returns the same as the built-in median, viz.
put median2("4.1,5.6,7.2,1.7,9.3,4.4,3.2") & "," & median2("4.1,7.2,1.7,9.3,4.4,3.2")
4.4,4.25
LSL
integer MAX_ELEMENTS = 10;
integer MAX_VALUE = 100;
default {
state_entry() {
list lst = [];
integer x = 0;
for(x=0 ; x<MAX_ELEMENTS ; x++) {
lst += llFrand(MAX_VALUE);
}
llOwnerSay("lst=["+llList2CSV(lst)+"]");
llOwnerSay("Geometric Mean: "+(string)llListStatistics(LIST_STAT_GEOMETRIC_MEAN, lst));
llOwnerSay(" Max: "+(string)llListStatistics(LIST_STAT_MAX, lst));
llOwnerSay(" Mean: "+(string)llListStatistics(LIST_STAT_MEAN, lst));
llOwnerSay(" Median: "+(string)llListStatistics(LIST_STAT_MEDIAN, lst));
llOwnerSay(" Min: "+(string)llListStatistics(LIST_STAT_MIN, lst));
llOwnerSay(" Num Count: "+(string)llListStatistics(LIST_STAT_NUM_COUNT, lst));
llOwnerSay(" Range: "+(string)llListStatistics(LIST_STAT_RANGE, lst));
llOwnerSay(" Std Dev: "+(string)llListStatistics(LIST_STAT_STD_DEV, lst));
llOwnerSay(" Sum: "+(string)llListStatistics(LIST_STAT_SUM, lst));
llOwnerSay(" Sum Squares: "+(string)llListStatistics(LIST_STAT_SUM_SQUARES, lst));
}
}
Output:
lst=[23.815209, 85.890704, 10.811144, 31.522696, 54.619416, 12.211729, 42.964463, 87.367889, 7.106129, 18.711078] Geometric Mean: 27.325070 Max: 87.367889 Mean: 37.502046 Median: 27.668953 Min: 7.106129 Num Count: 10.000000 Range: 80.261761 Std Dev: 29.819840 Sum: 375.020458 Sum Squares: 22067.040048
Lua
function median (numlist)
if type(numlist) ~= 'table' then return numlist end
table.sort(numlist)
if #numlist %2 == 0 then return (numlist[#numlist/2] + numlist[#numlist/2+1]) / 2 end
return numlist[math.ceil(#numlist/2)]
end
print(median({4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2}))
print(median({4.1, 7.2, 1.7, 9.3, 4.4, 3.2}))
Maple
Builtin
This works for numeric lists or arrays, and is designed for large data sets.
> Statistics:-Median( [ 1, 5, 3, 2, 4 ] );
3.
> Statistics:-Median( [ 1, 5, 3, 6, 2, 4 ] );
3.50000000000000
Using a sort
This solution can handle exact numeric inputs. Instead of inputting a container of some kind, it simply finds the median of its arguments.
median1 := proc()
local L := sort( [ args ] );
( L[ iquo( 1 + nargs, 2 ) ] + L[ 1 + iquo( nargs, 2 ) ] ) / 2
end proc:
For example:
> median1( 1, 5, 3, 2, 4 ); # 3
3
> median1( 1, 5, 3, 6, 4, 2 ); # 7/2
7/2
Mathematica / Wolfram Language
Built-in function:
Median[{1, 5, 3, 2, 4}]
Median[{1, 5, 3, 6, 4, 2}]
- Output:
3 7/2
Custom function:
mymedian[x_List]:=Module[{t=Sort[x],L=Length[x]},
If[Mod[L,2]==0,
(t[[L/2]]+t[[L/2+1]])/2
,
t[[(L+1)/2]]
]
]
Example of custom function:
mymedian[{1, 5, 3, 2, 4}]
mymedian[{1, 5, 3, 6, 4, 2}]
- Output:
3 7/2
MATLAB
If the input has an even number of elements, function returns the mean of the middle two values:
function medianValue = findmedian(setOfValues)
medianValue = median(setOfValues);
end
Maxima
/* built-in */
median([41, 56, 72, 17, 93, 44, 32]); /* 44 */
median([41, 72, 17, 93, 44, 32]); /* 85/2 */
min
('> sort med) ^median
(4.1 5.6 7.2 1.7 9.3 4.4 3.2) median puts!
(4.1 7.2 1.7 9.3 4.4 3.2) median puts!
- Output:
4.4 4.25
MiniScript
list.median = function()
self.sort
m = floor(self.len/2)
if self.len % 2 then return self[m]
return (self[m] + self[m-1]) * 0.5
end function
print [41, 56, 72, 17, 93, 44, 32].median
print [41, 72, 17, 93, 44, 32].median
- Output:
44 42.5
MUMPS
MEDIAN(X)
;X is assumed to be a list of numbers separated by "^"
;I is a loop index
;L is the length of X
;Y is a new array
QUIT:'$DATA(X) "No data"
QUIT:X="" "Empty Set"
NEW I,ODD,L,Y
SET L=$LENGTH(X,"^"),ODD=L#2,I=1
;The values in the vector are used as indices for a new array Y, which sorts them
FOR QUIT:I>L SET Y($PIECE(X,"^",I))=1,I=I+1
;Go to the median index, or the lesser of the middle if there is an even number of elements
SET J="" FOR I=1:1:$SELECT(ODD:L\2+1,'ODD:L/2) SET J=$ORDER(Y(J))
QUIT $SELECT(ODD:J,'ODD:(J+$ORDER(Y(J)))/2)
USER>W $$MEDIAN^ROSETTA("-1.3^2.43^3.14^17^2E-3") 3.14 USER>W $$MEDIAN^ROSETTA("-1.3^2.43^3.14^17^2E-3^4") 3.57 USER>W $$MEDIAN^ROSETTA("") Empty Set USER>W $$MEDIAN^ROSETTA No data
Nanoquery
import sort
def median(aray)
srtd = sort(aray)
alen = len(srtd)
return 0.5*( srtd[int(alen-1/2)] + srtd[int(alen/2)])
end
a = {4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2}
println a + " " + median(a)
a = {4.1, 7.2, 1.7, 9.3, 4.4, 3.2}
println a + " " + median(a)
NetRexx
/* NetRexx */
options replace format comments java crossref symbols nobinary
class RAvgMedian00 public
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
method median(lvector = java.util.List) public static returns Rexx
cvector = ArrayList(lvector) -- make a copy of input to ensure it's contents are preserved
Collections.sort(cvector, RAvgMedian00.RexxComparator())
kVal = ((Rexx cvector.get(cvector.size() % 2)) + (Rexx cvector.get((cvector.size() - 1) % 2))) / 2
return kVal
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
method median(rvector = Rexx[]) public static returns Rexx
return median(ArrayList(Arrays.asList(rvector)))
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
method show_median(lvector = java.util.List) public static returns Rexx
mVal = median(lvector)
say 'Meadian:' mVal.format(10, 6, 3, 6, 's')', Vector:' (Rexx lvector).space(0)
return mVal
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
method show_median(rvector = Rexx[]) public static returns Rexx
return show_median(ArrayList(Arrays.asList(rvector)))
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
method run_samples() public static
show_median([Rexx 10.0]) -- 10.0
show_median([Rexx 10.0, 9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0]) -- 5.5
show_median([Rexx 9, 8, 7, 6, 5, 4, 3, 2, 1]) -- 5.0
show_median([Rexx 1.0, 9, 2.0, 4.0]) -- 3.0
show_median([Rexx 3.0, 1, 4, 1.0, 5.0, 9, 7.0, 6.0]) -- 4.5
show_median([Rexx 3, 4, 1, -8.4, 7.2, 4, 1, 1.2]) -- 2.1
show_median([Rexx -1.2345678e+99, 2.3e+700]) -- 1.15e+700
show_median([Rexx 4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2]) -- 4.4
show_median([Rexx 4.1, 7.2, 1.7, 9.3, 4.4, 3.2]) -- 4.25
show_median([Rexx 28.207, 74.916, 51.695, 72.486, 51.118, 3.241, 73.807]) -- 51.695
show_median([Rexx 27.984, 89.172, 0.250, 66.316, 41.805, 60.043]) -- 50.924
show_median([Rexx 5.1, 2.6, 6.2, 8.8, 4.6, 4.1]) -- 4.85
show_median([Rexx 5.1, 2.6, 8.8, 4.6, 4.1]) -- 4.6
show_median([Rexx 4.4, 2.3, -1.7, 7.5, 6.6, 0.0, 1.9, 8.2, 9.3, 4.5]) -- 4.45
show_median([Rexx 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0.11]) -- 3.0
show_median([Rexx 10, 20, 30, 40, 50, -100, 4.7, -11e+2]) -- 15.0
show_median([Rexx 9.3, -2.0, 4.0, 7.3, 8.1, 4.1, -6.3, 4.2, -1.0, -8.4]) -- 4.05
show_median([Rexx 8.3, -3.6, 5.7, 2.3, 9.3, 5.4, -2.3, 6.3, 9.9]) -- 5.7
return
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
method main(args = String[]) public static
run_samples()
return
-- =============================================================================
class RAvgMedian00.RexxComparator implements Comparator
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
method compare(i1=Object, i2=Object) public returns int
i = Rexx i1
j = Rexx i2
if i < j then return -1
if i > j then return +1
else return 0
Output:
Meadian: 10.000000 , Vector: [10.0] Meadian: 5.500000 , Vector: [10.0,9.0,8.0,7.0,6.0,5.0,4.0,3.0,2.0,1.0] Meadian: 5.000000 , Vector: [9,8,7,6,5,4,3,2,1] Meadian: 3.000000 , Vector: [1.0,9,2.0,4.0] Meadian: 4.500000 , Vector: [3.0,1,4,1.0,5.0,9,7.0,6.0] Meadian: 2.100000 , Vector: [3,4,1,-8.4,7.2,4,1,1.2] Meadian: 1.150000E+700, Vector: [-1.2345678E+99,2.3e+700] Meadian: 4.400000 , Vector: [4.1,5.6,7.2,1.7,9.3,4.4,3.2] Meadian: 4.250000 , Vector: [4.1,7.2,1.7,9.3,4.4,3.2] Meadian: 51.695000 , Vector: [28.207,74.916,51.695,72.486,51.118,3.241,73.807] Meadian: 50.924000 , Vector: [27.984,89.172,0.250,66.316,41.805,60.043] Meadian: 4.850000 , Vector: [5.1,2.6,6.2,8.8,4.6,4.1] Meadian: 4.600000 , Vector: [5.1,2.6,8.8,4.6,4.1] Meadian: 4.450000 , Vector: [4.4,2.3,-1.7,7.5,6.6,0.0,1.9,8.2,9.3,4.5] Meadian: 3.000000 , Vector: [10,9,8,7,6,5,4,3,2,1,0,0,0,0,0.11] Meadian: 15.000000 , Vector: [10,20,30,40,50,-100,4.7,-1100] Meadian: 4.050000 , Vector: [9.3,-2.0,4.0,7.3,8.1,4.1,-6.3,4.2,-1.0,-8.4] Meadian: 5.700000 , Vector: [8.3,-3.6,5.7,2.3,9.3,5.4,-2.3,6.3,9.9]
NewLISP
; median.lsp
; oofoe 2012-01-25
(define (median lst)
(sort lst) ; Sorts in place.
(if (empty? lst)
nil
(letn ((n (length lst))
(h (/ (- n 1) 2)))
(if (zero? (mod n 2))
(div (add (lst h) (lst (+ h 1))) 2)
(lst h))
)))
(define (test lst) (println lst " -> " (median lst)))
(test '())
(test '(5 3 4))
(test '(5 4 2 3))
(test '(3 4 1 -8.4 7.2 4 1 1.2))
(exit)
Sample output:
() -> nil (5 3 4) -> 4 (5 4 2 3) -> 3.5 (3 4 1 -8.4 7.2 4 1 1.2) -> 2.1
Nim
import algorithm, strutils
proc median(xs: seq[float]): float =
var ys = xs
sort(ys, system.cmp[float])
0.5 * (ys[ys.high div 2] + ys[ys.len div 2])
var a = @[4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2]
echo formatFloat(median(a), precision = 0)
a = @[4.1, 7.2, 1.7, 9.3, 4.4, 3.2]
echo formatFloat(median(a), precision = 0)
Example Output:
4.4 4.25
Oberon-2
Oxford Oberon-2
MODULE Median;
IMPORT Out;
CONST
MAXSIZE = 100;
PROCEDURE Partition(VAR a: ARRAY OF REAL; left, right: INTEGER): INTEGER;
VAR
pValue,aux: REAL;
store,i,pivot: INTEGER;
BEGIN
pivot := right;
pValue := a[pivot];
aux := a[right];a[right] := a[pivot];a[pivot] := aux; (* a[pivot] <-> a[right] *)
store := left;
FOR i := left TO right -1 DO
IF a[i] <= pValue THEN
aux := a[store];a[store] := a[i];a[i]:=aux;
INC(store)
END
END;
aux := a[right];a[right] := a[store]; a[store] := aux;
RETURN store
END Partition;
(* QuickSelect algorithm *)
PROCEDURE Select(a: ARRAY OF REAL; left,right,k: INTEGER;VAR r: REAL);
VAR
pIndex, pDist : INTEGER;
BEGIN
IF left = right THEN r := a[left]; RETURN END;
pIndex := Partition(a,left,right);
pDist := pIndex - left + 1;
IF pDist = k THEN
r := a[pIndex];RETURN
ELSIF k < pDist THEN
Select(a,left, pIndex - 1, k, r)
ELSE
Select(a,pIndex + 1, right, k - pDist, r)
END
END Select;
PROCEDURE Median(a: ARRAY OF REAL;left,right: INTEGER): REAL;
VAR
idx,len : INTEGER;
r1,r2 : REAL;
BEGIN
len := right - left + 1;
idx := len DIV 2 + 1;
r1 := 0.0;r2 := 0.0;
Select(a,left,right,idx,r1);
IF ODD(len) THEN RETURN r1 END;
Select(a,left,right,idx - 1,r2);
RETURN (r1 + r2) / 2;
END Median;
VAR
ary: ARRAY MAXSIZE OF REAL;
r: REAL;
BEGIN
r := 0.0;
Out.Fixed(Median(ary,0,0),4,2);Out.Ln; (* empty *)
ary[0] := 5;
ary[1] := 3;
ary[2] := 4;
Out.Fixed(Median(ary,0,2),4,2);Out.Ln;
ary[0] := 5;
ary[1] := 4;
ary[2] := 2;
ary[3] := 3;
Out.Fixed(Median(ary,0,3),4,2);Out.Ln;
ary[0] := 3;
ary[1] := 4;
ary[2] := 1;
ary[3] := -8.4;
ary[4] := 7.2;
ary[5] := 4;
ary[6] := 1;
ary[7] := 1.2;
Out.Fixed(Median(ary,0,7),4,2);Out.Ln;
END Median.
Output:
0.00 4.00 3.50 2.10
Objeck
use Structure;
bundle Default {
class Median {
function : Main(args : String[]) ~ Nil {
numbers := FloatVector->New([4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2]);
DoMedian(numbers)->PrintLine();
numbers := FloatVector->New([4.1, 7.2, 1.7, 9.3, 4.4, 3.2]);
DoMedian(numbers)->PrintLine();
}
function : native : DoMedian(numbers : FloatVector) ~ Float {
if(numbers->Size() = 0) {
return 0.0;
}
else if(numbers->Size() = 1) {
return numbers->Get(0);
};
numbers->Sort();
i := numbers->Size() / 2;
if(numbers->Size() % 2 = 0) {
return (numbers->Get(i - 1) + numbers->Get(i)) / 2.0;
};
return numbers->Get(i);
}
}
}
OCaml
(* note: this modifies the input array *)
let median array =
let len = Array.length array in
Array.sort compare array;
(array.((len-1)/2) +. array.(len/2)) /. 2.0;;
let a = [|4.1; 5.6; 7.2; 1.7; 9.3; 4.4; 3.2|];;
median a;;
let a = [|4.1; 7.2; 1.7; 9.3; 4.4; 3.2|];;
median a;;
Octave
Of course Octave has its own median function we can use to check our implementation. The Octave's median function, however, does not handle the case you pass in a void vector.
function y = median2(v)
if (numel(v) < 1)
y = NA;
else
sv = sort(v);
l = numel(v);
if ( mod(l, 2) == 0 )
y = (sv(floor(l/2)+1) + sv(floor(l/2)))/2;
else
y = sv(floor(l/2)+1);
endif
endif
endfunction
a = [4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2];
b = [4.1, 7.2, 1.7, 9.3, 4.4, 3.2];
disp(median2(a)) % 4.4
disp(median(a))
disp(median2(b)) % 4.25
disp(median(b))
ooRexx
call testMedian .array~of(10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
call testMedian .array~of(10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, .11)
call testMedian .array~of(10, 20, 30, 40, 50, -100, 4.7, -11e2)
call testMedian .array~new
::routine testMedian
use arg numbers
say "numbers =" numbers~toString("l", ", ")
say "median =" median(numbers)
say
::routine median
use arg numbers
if numbers~isempty then return 0
-- make a copy so the sort does not alter the
-- original set. This also means this will
-- work with lists and queues as well
numbers = numbers~makearray
-- sort and return the middle element
numbers~sortWith(.numbercomparator~new)
size = numbers~items
-- this handles the odd value too
return numbers[size%2 + size//2]
-- a custom comparator that sorts strings as numeric values rather than
-- strings
::class numberComparator subclass comparator
::method compare
use strict arg left, right
-- perform the comparison on the names. By subtracting
-- the two and returning the sign, we give the expected
-- results for the compares
return (left - right)~sign
Oz
declare
fun {Median Xs}
Len = {Length Xs}
Mid = Len div 2 + 1 %% 1-based index
Sorted = {Sort Xs Value.'<'}
in
if {IsOdd Len} then {Nth Sorted Mid}
else ({Nth Sorted Mid} + {Nth Sorted Mid-1}) / 2.0
end
end
in
{Show {Median [4.1 5.6 7.2 1.7 9.3 4.4 3.2]}}
{Show {Median [4.1 7.2 1.7 9.3 4.4 3.2]}}
PARI/GP
Sorting solution.
median(v)={
vecsort(v)[#v\2]
};
Linear-time solution, mostly proof-of-concept but perhaps suitable for large lists.
BFPRT(v,k=#v\2)={
if(#v<15, return(vecsort(v)[k]));
my(u=List(),pivot,left=List(),right=List());
forstep(i=1,#v-4,5,
listput(u,BFPRT([v[i],v[i+1],v[i+2],v[i+3],v[i+4]]))
);
pivot=BFPRT(Vec(u));
u=0;
for(i=1,#v,
if(v[i]<pivot,
listput(left,v[i])
,
listput(right,v[i])
)
);
if(k>#left,
BFPRT(right, k-#left)
,
BFPRT(left, k)
)
};
Pascal
Program AveragesMedian(output);
type
TDoubleArray = array of double;
procedure bubbleSort(var list: TDoubleArray);
var
i, j, n: integer;
t: double;
begin
n := length(list);
for i := n downto 2 do
for j := 0 to i - 1 do
if list[j] > list[j + 1] then
begin
t := list[j];
list[j] := list[j + 1];
list[j + 1] := t;
end;
end;
function Median(aArray: TDoubleArray): double;
var
lMiddleIndex: integer;
begin
bubbleSort(aArray);
lMiddleIndex := (high(aArray) - low(aArray)) div 2;
if Odd(Length(aArray)) then
Median := aArray[lMiddleIndex + 1]
else
Median := (aArray[lMiddleIndex + 1] + aArray[lMiddleIndex]) / 2;
end;
var
A: TDoubleArray;
i: integer;
begin
randomize;
setlength(A, 7);
for i := low(A) to high(A) do
begin
A[i] := 100 * random;
write (A[i]:7:3, ' ');
end;
writeln;
writeln('Median: ', Median(A):7:3);
setlength(A, 6);
for i := low(A) to high(A) do
begin
A[i] := 100 * random;
write (A[i]:7:3, ' ');
end;
writeln;
writeln('Median: ', Median(A):7:3);
end.
Output:
% ./Median 28.207 74.916 51.695 72.486 51.118 3.241 73.807 Median: 51.695 27.984 89.172 0.250 66.316 41.805 60.043 Median: 50.924
Perl
sub median {
my @a = sort {$a <=> $b} @_;
return ($a[$#a/2] + $a[@a/2]) / 2;
}
Phix
The obvious simple way:
with javascript_semantics function median(sequence s) atom res=0 integer l = length(s), k = floor((l+1)/2) if l then s = sort(s) res = s[k] if remainder(l,2)=0 then res = (res+s[k+1])/2 end if end if return res end function
It is also possible to use the quick_select routine for a small (20%) performance improvement, which as suggested below may with luck be magnified by retaining any partially sorted results.
with javascript_semantics function medianq(sequence s) atom res=0, tmp integer l = length(s), k = floor((l+1)/2) if l then {s,res} = quick_select(s,k) if remainder(l,2)=0 then {s,tmp} = quick_select(s,k+1) res = (res+tmp)/2 end if end if return res -- (or perhaps return {s,res}) end function
Phixmonti
include ..\Utilitys.pmt
def median /# l -- n #/
sort len 2 / >ps
tps .5 + int 2 slice nip
ps> dup int != if
1 get nip
else
sum 2 /
endif
enddef
( 4.1 5.6 7.2 1.7 9.3 4.4 3.2 ) median ?
( 4.1 7.2 1.7 9.3 4.4 3.2 ) median ?
PHP
This solution uses the sorting method of finding the median.
function median($arr)
{
sort($arr);
$count = count($arr); //count the number of values in array
$middleval = floor(($count-1)/2); // find the middle value, or the lowest middle value
if ($count % 2) { // odd number, middle is the median
$median = $arr[$middleval];
} else { // even number, calculate avg of 2 medians
$low = $arr[$middleval];
$high = $arr[$middleval+1];
$median = (($low+$high)/2);
}
return $median;
}
echo median(array(4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2)) . "\n"; // 4.4
echo median(array(4.1, 7.2, 1.7, 9.3, 4.4, 3.2)) . "\n"; // 4.25
Picat
go =>
Lists = [
[1.121,10.3223,3.41,12.1,0.01],
1..10,
1..11,
[3],
[3,4],
[],
[4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2],
[4.1, 7.2, 1.7, 9.3, 4.4, 3.2],
[5.1, 2.6, 6.2, 8.8, 4.6, 4.1],
[5.1, 2.6, 8.8, 4.6, 4.1]],
foreach(List in Lists)
println([List, median=median(List)])
end,
nl.
median([]) = undef.
median([X]) = X.
median(L) = cond(Len mod 2 == 1, LL[H+1], avg([LL[H],LL[H+1]])) =>
Len = L.length,
H = Len // 2,
LL = sort(L).
- Output:
[[1.121,10.3223,3.41,12.1,0.01],median = 3.41] [[1,2,3,4,5,6,7,8,9,10],median = 5.5] [[1,2,3,4,5,6,7,8,9,10,11],median = 6] [[3],median = 3] [[3,4],median = 3.5] [[],median = undef] [[4.1,5.6,7.2,1.7,9.300000000000001,4.4,3.2],median = 4.4] [[4.1,7.2,1.7,9.300000000000001,4.4,3.2],median = 4.25] [[5.1,2.6,6.2,8.800000000000001,4.6,4.1],median = 4.85] [[5.1,2.6,8.800000000000001,4.6,4.1],median = 4.6]
PicoLisp
(de median (Lst)
(let N (length Lst)
(if (bit? 1 N)
(get (sort Lst) (/ (inc N) 2))
(setq Lst (nth (sort Lst) (/ N 2)))
(/ (+ (car Lst) (cadr Lst)) 2) ) ) )
(scl 2)
(prinl (round (median (1.0 2.0 3.0))))
(prinl (round (median (1.0 2.0 3.0 4.0))))
(prinl (round (median (5.1 2.6 6.2 8.8 4.6 4.1))))
(prinl (round (median (5.1 2.6 8.8 4.6 4.1))))
Output:
2.00 2.50 4.85 4.60
PL/I
call sort(A);
n = dimension(A,1);
if iand(n,1) = 1 then /* an odd number of elements */
median = A(n/2);
else /* an even number of elements */
median = (a(n/2) + a(trunc(n/2)+1) )/2;
PowerShell
This function returns an object containing the minimal amount of statistical data, including Median, and could be modified to take input directly from the pipeline.
All statistical properties could easily be added to the output object.
function Measure-Data
{
[CmdletBinding()]
[OutputType([PSCustomObject])]
Param
(
[Parameter(Mandatory=$true,
Position=0)]
[double[]]
$Data
)
Begin
{
function Get-Mode ([double[]]$Data)
{
if ($Data.Count -gt ($Data | Select-Object -Unique).Count)
{
$groups = $Data | Group-Object | Sort-Object -Property Count -Descending
return ($groups | Where-Object {[double]$_.Count -eq [double]$groups[0].Count}).Name | ForEach-Object {[double]$_}
}
else
{
return $null
}
}
function Get-StandardDeviation ([double[]]$Data)
{
$variance = 0
$average = $Data | Measure-Object -Average | Select-Object -Property Count, Average
foreach ($number in $Data)
{
$variance += [Math]::Pow(($number - $average.Average),2)
}
return [Math]::Sqrt($variance / ($average.Count-1))
}
function Get-Median ([double[]]$Data)
{
if ($Data.Count % 2)
{
return $Data[[Math]::Floor($Data.Count/2)]
}
else
{
return ($Data[$Data.Count/2], $Data[$Data.Count/2-1] | Measure-Object -Average).Average
}
}
}
Process
{
$Data = $Data | Sort-Object
$Data | Measure-Object -Maximum -Minimum -Sum -Average |
Select-Object -Property Count,
Sum,
Minimum,
Maximum,
@{Name='Range'; Expression={$_.Maximum - $_.Minimum}},
@{Name='Mean' ; Expression={$_.Average}} |
Add-Member -MemberType NoteProperty -Name Median -Value (Get-Median $Data) -PassThru |
Add-Member -MemberType NoteProperty -Name StandardDeviation -Value (Get-StandardDeviation $Data) -PassThru |
Add-Member -MemberType NoteProperty -Name Mode -Value (Get-Mode $Data) -PassThru
}
}
$statistics = Measure-Data 4, 5, 6, 7, 7, 7, 8, 1, 1, 1, 2, 3
$statistics
- Output:
Count : 12 Sum : 52 Minimum : 1 Maximum : 8 Range : 7 Mean : 4.33333333333333 Median : 4.5 StandardDeviation : 2.67423169368609 Mode : {1, 7}
Median only:
$statistics.Median
- Output:
4.5
Processing
void setup() {
float[] numbers = {3.1, 4.1, 5.9, 2.6, 5.3, 5.8};
println(median(numbers));
numbers = shorten(numbers);
println(median(numbers));
}
float median(float[] nums) {
nums = sort(nums);
float median = (nums[(nums.length - 1) / 2] + nums[nums.length / 2]) / 2.0;
return median;
}
- Output:
4.7 4.1
Prolog
median(L, Z) :-
length(L, Length),
I is Length div 2,
Rem is Length rem 2,
msort(L, S),
maplist(sumlist, [[I, Rem], [I, 1]], Mid),
maplist(nth1, Mid, [S, S], X),
sumlist(X, Y),
Z is Y/2.
Pure
Inspired by the Haskell version.
median x = (/(2-rem)) $ foldl1 (+) $ take (2-rem) $ drop (mid-(1-rem)) $ sort (<=) x
when len = # x;
mid = len div 2;
rem = len mod 2;
end;
Output:
> median [1, 3, 5]; 3.0 > median [1, 2, 3, 4]; 2.5
PureBasic
Procedure.d median(Array values.d(1), length.i)
If length = 0 : ProcedureReturn 0.0 : EndIf
SortArray(values(), #PB_Sort_Ascending)
If length % 2
ProcedureReturn values(length / 2)
EndIf
ProcedureReturn 0.5 * (values(length / 2 - 1) + values(length / 2))
EndProcedure
Procedure.i readArray(Array values.d(1))
Protected length.i, i.i
Read.i length
ReDim values(length - 1)
For i = 0 To length - 1
Read.d values(i)
Next
ProcedureReturn i
EndProcedure
Dim floats.d(0)
Restore array1
length.i = readArray(floats())
Debug median(floats(), length)
Restore array2
length.i = readArray(floats())
Debug median(floats(), length)
DataSection
array1:
Data.i 7
Data.d 4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2
array2:
Data.i 6
Data.d 4.1, 7.2, 1.7, 9.3, 4.4, 3.2
EndDataSection
Python
def median(aray):
srtd = sorted(aray)
alen = len(srtd)
return 0.5*( srtd[(alen-1)//2] + srtd[alen//2])
a = (4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2)
print a, median(a)
a = (4.1, 7.2, 1.7, 9.3, 4.4, 3.2)
print a, median(a)
R
R has its built-in median function.
omedian <- function(v) {
if ( length(v) < 1 )
NA
else {
sv <- sort(v)
l <- length(sv)
if ( l %% 2 == 0 )
(sv[floor(l/2)+1] + sv[floor(l/2)])/2
else
sv[floor(l/2)+1]
}
}
a <- c(4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2)
b <- c(4.1, 7.2, 1.7, 9.3, 4.4, 3.2)
print(median(a)) # 4.4
print(omedian(a))
print(median(b)) # 4.25
print(omedian(b))
Racket
#lang racket
(define (median numbers)
(define sorted (list->vector (sort (vector->list numbers) <)))
(define count (vector-length numbers))
(if (zero? count)
#f
(/ (+ (vector-ref sorted (floor (/ (sub1 count) 2)))
(vector-ref sorted (floor (/ count 2))))
2)))
(median '#(5 3 4)) ;; 4
(median '#()) ;; #f
(median '#(5 4 2 3)) ;; 7/2
(median '#(3 4 1 -8.4 7.2 4 1 1.2)) ;; 2.1
Raku
(formerly Perl 6)
sub median {
my @a = sort @_;
return (@a[(*-1) div 2] + @a[* div 2]) / 2;
}
Notes:
- The div operator does integer division. The / operator (rational number division) would work too, since the array subscript automatically coerces to Int, but using div is more explicit (i.e. clearer to readers) as well as faster, and thus recommended in cases like this.
- The * inside the subscript stands for the array's length (see documentation).
In a slightly more compact way:
sub median { @_.sort[(*-1)/2, */2].sum / 2 }
REBOL
median: func [
"Returns the midpoint value in a series of numbers; half the values are above, half are below."
block [any-block!]
/local len mid
][
if empty? block [return none]
block: sort copy block
len: length? block
mid: to integer! len / 2
either odd? len [
pick block add 1 mid
][
(block/:mid) + (pick block add 1 mid) / 2
]
]
ReScript
let median = (arr) =>
{
let float_compare = (a, b) => {
let diff = a -. b
if diff == 0.0 { 0 } else
if diff > 0.0 { 1 } else { -1 }
}
let _ = Js.Array2.sortInPlaceWith(arr, float_compare)
let count = Js.Array.length(arr)
// find the middle value, or the lowest middle value
let middleval = ((count - 1) / 2)
let median =
if (mod(count, 2) != 0) { // odd number, middle is the median
arr[middleval]
} else { // even number, calculate avg of 2 medians
let low = arr[middleval]
let high = arr[middleval+1]
((low +. high) /. 2.0)
}
median
}
Js.log(median([4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2]))
Js.log(median([4.1, 7.2, 1.7, 9.3, 4.4, 3.2]))
- Output:
$ bsc median.res > median.bs.js $ node median.bs.js 4.4 4.25
REXX
/*REXX program finds the median of a vector (and displays the vector and median).*/
/* ══════════vector════════════ ══show vector═══ ════════show result═══════════ */
v= 1 9 2 4 ; say "vector" v; say 'median──────►' median(v); say
v= 3 1 4 1 5 9 7 6 ; say "vector" v; say 'median──────►' median(v); say
v= '3 4 1 -8.4 7.2 4 1 1.2'; say "vector" v; say 'median──────►' median(v); say
v= -1.2345678e99 2.3e700 ; say "vector" v; say 'median──────►' median(v); say
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
eSORT: procedure expose @. #; parse arg $; #= words($) /*$: is the vector. */
do g=1 for #; @.g= word($, g); end /*g*/ /*convert list──►array*/
h=# /*#: number elements.*/
do while h>1; h= h % 2 /*cut entries by half.*/
do i=1 for #-h; j= i; k= h + i /*sort lower section. */
do while @.k<@.j; parse value @.j @.k with @.k @.j /*swap.*/
if h>=j then leave; j= j - h; k= k - h /*diminish J and K.*/
end /*while @.k<@.j*/
end /*i*/
end /*while h>1*/ /*end of exchange sort*/
return
/*──────────────────────────────────────────────────────────────────────────────────────*/
median: procedure; call eSORT arg(1); m= # % 2 /* % is REXX's integer division.*/
n= m + 1 /*N: the next element after M. */
if # // 2 then return @.n /*[odd?] // ◄───REXX's ÷ remainder*/
return (@.m + @.n) / 2 /*process an even─element vector. */
- output:
vector: 1 9 2 4 median──────► 3 vector: 3 1 4 1 5 9 7 6 median──────► 4.5 vector: 3 4 1 -8.4 7.2 4 1 1.2 median──────► 2.1 vector: -1.2345678e99 2.3e700 median──────► 1.15000000E+700
Ring
aList = [5,4,2,3]
see "medium : " + median(aList) + nl
func median aray
srtd = sort(aray)
alen = len(srtd)
if alen % 2 = 0
return (srtd[alen/2] + srtd[alen/2 + 1]) / 2.0
else return srtd[ceil(alen/2)] ok
RPL
≪ SORT DUP SIZE 1 + 2 / DUP2 FLOOR GET ROT ROT CEIL GET + 2 / ≫ 'MDIAN' STO
SORT
became a standard RPL instruction in 1993, with the introduction of the HP-48G. For earlier RPL versions, users have to call the sorting program demonstrated here.
Ruby
def median(ary)
return nil if ary.empty?
mid, rem = ary.length.divmod(2)
if rem == 0
ary.sort[mid-1,2].inject(:+) / 2.0
else
ary.sort[mid]
end
end
p median([]) # => nil
p median([5,3,4]) # => 4
p median([5,4,2,3]) # => 3.5
p median([3,4,1,-8.4,7.2,4,1,1.2]) # => 2.1
Alternately:
def median(aray)
srtd = aray.sort
alen = srtd.length
(srtd[(alen-1)/2] + srtd[alen/2]) / 2.0
end
Run BASIC
sqliteconnect #mem, ":memory:"
mem$ = "CREATE TABLE med (x float)"
#mem execute(mem$)
a$ ="4.1,5.6,7.2,1.7,9.3,4.4,3.2" :gosub [median]
a$ ="4.1,7.2,1.7,9.3,4.4,3.2" :gosub [median]
a$ ="4.1,4,1.2,6.235,7868.33" :gosub [median]
a$ ="1,5,3,2,4" :gosub [median]
a$ ="1,5,3,6,4,2" :gosub [median]
a$ ="4.4,2.3,-1.7,7.5,6.6,0.0,1.9,8.2,9.3,4.5" :gosub [median]'
end
[median]
#mem execute("DELETE FROM med")
for i = 1 to 100
v$ = word$( a$, i, ",")
if v$ = "" then exit for
mem$ = "INSERT INTO med values(";v$;")"
#mem execute(mem$)
next i
mem$ = "SELECT AVG(x) as median FROM (SELECT x FROM med
ORDER BY x LIMIT 2 - (SELECT COUNT(*) FROM med) % 2
OFFSET (SELECT (COUNT(*) - 1) / 2
FROM med))"
#mem execute(mem$)
#row = #mem #nextrow()
median = #row median()
print " Median :";median;chr$(9);" Values:";a$
RETURN
Output:
Median :4.4 Values:4.1,5.6,7.2,1.7,9.3,4.4,3.2 Median :4.25 Values:4.1,7.2,1.7,9.3,4.4,3.2 Median :4.1 Values:4.1,4,1.2,6.235,7868.33 Median :3.0 Values:1,5,3,2,4 Median :3.5 Values:1,5,3,6,4,2 Median :4.45 Values:4.4,2.3,-1.7,7.5,6.6,0.0,1.9,8.2,9.3,4.5
Rust
Sorting, then obtaining the median element:
fn median(mut xs: Vec<f64>) -> f64 {
// sort in ascending order, panic on f64::NaN
xs.sort_by(|x,y| x.partial_cmp(y).unwrap() );
let n = xs.len();
if n % 2 == 0 {
(xs[n/2] + xs[n/2 - 1]) / 2.0
} else {
xs[n/2]
}
}
fn main() {
let nums = vec![2.,3.,5.,0.,9.,82.,353.,32.,12.];
println!("{:?}", median(nums))
}
- Output:
9
Scala
(See the Scala discussion on Mean for more information.)
def median[T](s: Seq[T])(implicit n: Fractional[T]) = {
import n._
val (lower, upper) = s.sortWith(_<_).splitAt(s.size / 2)
if (s.size % 2 == 0) (lower.last + upper.head) / fromInt(2) else upper.head
}
This isn't really optimal. The methods splitAt and last are O(n/2) on many sequences, and then there's the lower bound imposed by the sort. Finally, we call size two times, and it can be O(n).
Scheme
Using Rosetta Code's bubble-sort function
(define (median l)
(* (+ (list-ref (bubble-sort l >) (round (/ (- (length l) 1) 2)))
(list-ref (bubble-sort l >) (round (/ (length l) 2)))) 0.5))
Using SRFI-95:
(define (median l)
(* (+ (list-ref (sort l less?) (round (/ (- (length l) 1) 2)))
(list-ref (sort l less?) (round (/ (length l) 2)))) 0.5))
Seed7
$ include "seed7_05.s7i";
include "float.s7i";
const type: floatList is array float;
const func float: median (in floatList: floats) is func
result
var float: median is 0.0;
local
var floatList: sortedFloats is 0 times 0.0;
begin
sortedFloats := sort(floats);
if odd(length(sortedFloats)) then
median := sortedFloats[succ(length(sortedFloats)) div 2];
else
median := 0.5 * (sortedFloats[length(sortedFloats) div 2] +
sortedFloats[succ(length(sortedFloats) div 2)]);
end if;
end func;
const proc: main is func
local
const floatList: flist1 is [] (5.1, 2.6, 6.2, 8.8, 4.6, 4.1);
const floatList: flist2 is [] (5.1, 2.6, 8.8, 4.6, 4.1);
begin
writeln("flist1 median is " <& median(flist1) digits 2 lpad 7); # 4.85
writeln("flist2 median is " <& median(flist2) digits 2 lpad 7); # 4.60
end func;
SenseTalk
SenseTalk has a built-in median function. This example also shows the implementation of a customMedian function that returns the same results.
put the median of [4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2]
put the median of [4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2, 6.6]
put customMedian of [4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2]
put customMedian of [4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2, 6.6]
to handle customMedian of list
sort list
if the number of items in list is an even number then
set lowMid to the number of items in list divided by 2
return (item lowMid of list + item lowMid+1 of list) / 2
else
return the middle item of list
end if
end customMedian
Output:
4.4
5
4.4
5
Sidef
func median(arry) {
var srtd = arry.sort;
var alen = srtd.length;
srtd[(alen-1)/2]+srtd[alen/2] / 2;
}
Slate
s@(Sequence traits) median
[
s isEmpty
ifTrue: [Nil]
ifFalse:
[| sorted |
sorted: s sort.
sorted length `cache isEven
ifTrue: [(sorted middle + (sorted at: sorted indexMiddle - 1)) / 2]
ifFalse: [sorted middle]]
].
inform: { 4.1 . 5.6 . 7.2 . 1.7 . 9.3 . 4.4 . 3.2 } median.
inform: { 4.1 . 7.2 . 1.7 . 9.3 . 4.4 . 3.2 } median.
Smalltalk
OrderedCollection extend [
median [
self size = 0
ifFalse: [ |s l|
l := self size.
s := self asSortedCollection.
(l rem: 2) = 0
ifTrue: [ ^ ((s at: (l//2 + 1)) + (s at: (l//2))) / 2 ]
ifFalse: [ ^ s at: (l//2 + 1) ]
]
ifTrue: [ ^nil ]
]
].
{ 4.1 . 5.6 . 7.2 . 1.7 . 9.3 . 4.4 . 3.2 } asOrderedCollection
median displayNl.
{ 4.1 . 7.2 . 1.7 . 9.3 . 4.4 . 3.2 } asOrderedCollection
median displayNl.
Stata
Use summarize to compute the median of a variable (as well as other basic statistics).
set obs 100000
gen x=rbeta(0.2,1.3)
quietly summarize x, detail
display r(p50)
Here is a straightforward implementation using sort.
program calcmedian, rclass sortpreserve
sort `1'
if mod(_N,2)==0 {
return scalar p50=(`1'[_N/2]+`1'[_N/2+1])/2
}
else {
return scalar p50=`1'[(_N-1)/2]
}
end
calcmedian x
display r(p50)
Swift
A full implementation
// Utility to aid easy type conversion
extension Double {
init(withNum v: any Numeric) {
switch v {
case let ii as any BinaryInteger: self.init(ii)
case let ff as any BinaryFloatingPoint: self.init(ff)
default: self.init()
}
}
}
extension Array where Element: Numeric & Comparable {
// Helper func for random element in range
func randomElement(within: Range<Int>) -> Element {
return self[.random(in: within)]
}
mutating func median() -> Double? {
switch self.count {
case 0: return nil
case 1: return Double(withNum: self[0])
case 2: return self.reduce(0, {sum,this in sum + Double(withNum: this)/2.0})
default: break
}
let pTarget: Int = self.count / 2 + 1
let resultSetLen: Int = self.count.isMultiple(of: 2) ? 2 : 1
func divideAndConquer(bottom: Int, top: Int, goal: Int) -> Int {
var (lower,upper) = (bottom,top)
while true {
let splitVal = self.randomElement(within: lower..<upper)
let partitionIndex = self.partition(subrange: lower..<upper, by: {$0 > splitVal})
switch partitionIndex {
case goal: return partitionIndex
case ..<goal: lower = partitionIndex
default: upper = partitionIndex
}
}
}
// Split just above the 'median point'
var pIndex = divideAndConquer(bottom: 0, top: self.count, goal: pTarget)
// Shove the highest 'low' values into the result slice
pIndex = divideAndConquer(bottom: 0, top: pIndex, goal: pIndex - resultSetLen)
// Average the contents of the result slice
return self[pIndex..<pIndex + resultSetLen]
.reduce(0.0, {sum,this in sum + Double(withNum: this)/Double(withNum: resultSetLen)})
}
}
Usage:
var c: [Double] = (0...100).map {_ in Double.random(in: 0...100)}
print(c.median())
Tcl
proc median args {
set list [lsort -real $args]
set len [llength $list]
# Odd number of elements
if {$len & 1} {
return [lindex $list [expr {($len-1)/2}]]
}
# Even number of elements
set idx2 [expr {$len/2}]
set idx1 [expr {$idx2-1}]
return [expr {
([lindex $list $idx1] + [lindex $list $idx2])/2.0
}]
}
puts [median 3.0 4.0 1.0 -8.4 7.2 4.0 1.0 1.2]; # --> 2.1
TI-83 BASIC
Using the built-in function:
median({1.1, 2.5, 0.3241})
TI-89 BASIC
median({3, 4, 1, -8.4, 7.2, 4, 1, 1})
Ursala
the simple way (sort first and then look in the middle)
#import std
#import flo
median = fleq-<; @K30K31X eql?\~&rh div\2.+ plus@lzPrhPX
test program, once with an odd length and once with an even length vector
#cast %eW
examples =
median~~ (
<9.3,-2.0,4.0,7.3,8.1,4.1,-6.3,4.2,-1.0,-8.4>,
<8.3,-3.6,5.7,2.3,9.3,5.4,-2.3,6.3,9.9>)
output:
(4.050000e+00,5.700000e+00)
Vala
Requires --pkg posix -X -lm
compilation flags in order to use POSIX qsort, and to have access to math library.
int compare_numbers(void* a_ref, void* b_ref) {
double a = *(double*) a_ref;
double b = *(double*) b_ref;
return a > b ? 1 : a < b ? -1 : 0;
}
double median(double[] elements) {
double[] clone = elements;
Posix.qsort(clone, clone.length, sizeof(double), compare_numbers);
double middle = clone.length / 2.0;
int first = (int) Math.floor(middle);
int second = (int) Math.ceil(middle);
return (clone[first] + clone[second]) / 2;
}
void main() {
double[] array1 = {2, 4, 6, 1, 7, 3, 5};
double[] array2 = {2, 4, 6, 1, 7, 3, 5, 8};
print(@"$(median(array1)) $(median(array2))\n");
}
VBA
Uses quick select.
Private Function medianq(s As Variant) As Double
Dim res As Double, tmp As Integer
Dim l As Integer, k As Integer
res = 0
l = UBound(s): k = WorksheetFunction.Floor_Precise((l + 1) / 2, 1)
If l Then
res = quick_select(s, k)
If l Mod 2 = 0 Then
tmp = quick_select(s, k + 1)
res = (res + tmp) / 2
End If
End If
medianq = res
End Function
Public Sub main2()
s = [{4, 2, 3, 5, 1, 6}]
Debug.Print medianq(s)
End Sub
- Output:
3,5
Vedit macro language
This is a simple implementation for positive integers using sorting. The data is stored in current edit buffer in ascii representation. The values must be right justified.
The result is returned in text register @10. In case of even number of items, the lower middle value is returned.
Sort(0, File_Size, NOCOLLATE+NORESTORE)
EOF Goto_Line(Cur_Line/2)
Reg_Copy(10, 1)
V (Vlang)
fn main() {
println(median([3, 1, 4, 1])) // prints 2
println(median([3, 1, 4, 1, 5])) // prints 3
}
fn median(aa []int) int {
mut a := aa.clone()
a.sort()
half := a.len / 2
mut m := a[half]
if a.len%2 == 0 {
m = (m + a[half-1]) / 2
}
return m
}
- Output:
2 3
If you use math.stats module the list parameter must be sorted
import math.stats
fn main() {
println(stats.median<int>([1, 1, 3, 4])) // prints 2
println(stats.median<int>([1, 1, 3, 4, 5])) // prints 3
}
Wortel
@let {
; iterative
med1 &l @let {a @sort l s #a i @/s 2 ?{%%s 2 ~/ 2 +`-i 1 a `i a `i a}}
; tacit
med2 ^(\~/2 @sum @(^(\&![#~f #~c] \~/2 \~-1 #) @` @id) @sort)
[[
!med1 [4 2 5 2 1]
!med1 [4 5 2 1]
!med2 [4 2 5 2 1]
!med2 [4 5 2 1]
]]
}
Returns:
[2 3 2 3]
Wren
import "./sort" for Sort, Find
import "./math" for Nums
import "./queue" for PriorityQueue
var lists = [
[5, 3, 4],
[3, 4, 1, -8.4, 7.2, 4, 1, 1.2]
]
for (l in lists) {
// sort and then find median
var l2 = Sort.merge(l)
System.print(Nums.median(l2))
// using a priority queue
var pq = PriorityQueue.new()
for (e in l) pq.push(e, -e)
var c = pq.count
var v = pq.values
var m = (c % 2 == 1) ? v[(c/2).floor] : (v[c/2] + v[c/2-1])/2
System.print(m)
// using quickselect
if (c % 2 == 1) {
System.print(Find.quick(l, (c/2).floor))
} else {
var m1 = Find.quick(l, c/2-1)
var m2 = Find.quick(l, c/2)
System.print((m1 + m2)/2)
}
System.print()
}
- Output:
4 4 4 2.1 2.1 2.1
XPL0
func real Median(Size, Array); \Return median value of Array
int Size; real Array;
int I, J, MinJ;
real Temp;
[for I:= 0 to Size/2 do \partial selection sort
[MinJ:= I;
for J:= I+1 to Size-1 do
if Array(J) < Array(MinJ) then MinJ:= J;
Temp:= Array(I); Array(I):= Array(MinJ); Array(MinJ):= Temp;
];
if rem(Size/2) = 1 then return Array(Size/2)
else return (Array(Size/2-1) + Array(Size/2)) / 2.;
];
[RlOut(0, Median(3, [5.0, 3.0, 4.0])); CrLf(0);
RlOut(0, Median(8, [3.0, 4.0, 1.0, -8.4, 7.2, 4.0, 1.0, 1.2])); CrLf(0);
]
- Output:
4.00000 2.10000
Yabasic
sub floor(x)
return int(x + .05)
end sub
sub ceil(x)
if x > int(x) x = x + 1
return x
end sub
SUB ASort$(matriz$())
local last, gap, first, tempi$, tempj$, i, j
last = arraysize(matriz$(), 1)
gap = floor(last / 10) + 1
while(TRUE)
first = gap + 1
for i = first to last
tempi$ = matriz$(i)
j = i - gap
while(TRUE)
tempj$ = matriz$(j)
if (tempi$ >= tempj$) then
j = j + gap
break
end if
matriz$(j+gap) = tempj$
if j <= gap then
break
end if
j = j - gap
wend
matriz$(j) = tempi$
next i
if gap = 1 then
return
else
gap = floor(gap / 3.5) + 1
end if
wend
END SUB
sub median(numlist$)
local numlist$(1), n
n = token(numlist$, numlist$(), ", ")
ASort$(numlist$())
if mod(n, 2) = 0 then return (val(numlist$(n / 2)) + val(numlist$(n / 2 + 1))) / 2 end if
return val(numlist$(ceil(n / 2)))
end sub
print median("4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2") // 4.4
print median("4.1, 7.2, 1.7, 9.3, 4.4, 3.2") // 4.25
zkl
Using the Quickselect algorithm#zkl for O(n) time:
var quickSelect=Import("quickSelect").qselect;
fcn median(xs){
n:=xs.len();
if (n.isOdd) return(quickSelect(xs,n/2));
( quickSelect(xs,n/2-1) + quickSelect(xs,n/2) )/2;
}
median(T( 5.1, 2.6, 6.2, 8.8, 4.6, 4.1 )); //-->4.85
median(T( 5.1, 2.6, 8.8, 4.6, 4.1 )); //-->4.6
Zoea
program: median
case: 1
input: [4,5,6,8,9]
output: 6
case: 2
input: [2,5,6]
output: 5
case: 3
input: [2,5,6,8]
output: 5.5
Zoea Visual
zonnon
module Averages;
type
Vector = array {math} * of real;
procedure Partition(var a: Vector; left, right: integer): integer;
var
pValue,aux: real;
store,i,pivot: integer;
begin
pivot := right;
pValue := a[pivot];
aux := a[right];a[right] := a[pivot];a[pivot] := aux; (* a[pivot] <-> a[right] *)
store := left;
for i := left to right -1 do
if a[i] <= pValue then
aux := a[store];a[store] := a[i];a[i]:=aux;
inc(store)
end
end;
aux := a[right];a[right] := a[store]; a[store] := aux;
return store
end Partition;
(* QuickSelect algorithm *)
procedure Select(a: Vector; left,right,k: integer;var r: real);
var
pIndex, pDist : integer;
begin
if left = right then r := a[left]; return end;
pIndex := Partition(a,left,right);
pDist := pIndex - left + 1;
if pDist = k then
r := a[pIndex];return
elsif k < pDist then
Select(a,left, pIndex - 1, k, r)
else
Select(a,pIndex + 1, right, k - pDist, r)
end
end Select;
procedure Median(a: Vector): real;
var
idx: integer;
r1,r2 : real;
begin
idx := len(a) div 2 + 1;
r1 := 0.0;r2 := 0.0;
Select(a,0,len(a) - 1,idx,r1);
if odd(len(a)) then return r1 end;
Select(a,0,len(a) - 1,idx - 1,r2);
return (r1 + r2) / 2;
end Median;
var
ary: Vector;
r: real;
begin
ary := new Vector(3);
ary := [5.0,3.0,4.0];
writeln(Median(ary):10:2);
ary := new Vector(4);
ary := [5.0,4.0,2.0,3.0];
writeln(Median(ary):10:2);
ary := new Vector(8);
ary := [3.0,4.0,1.0,-8.4,7.2,4.0,1.0,1.2];
writeln(Median(ary):10:2)
end Averages.
4 3,5 2,1
- Sorting
- E examples needing attention
- Programming Tasks
- Probability and statistics
- 11l
- AArch64 Assembly
- Action!
- Action! Tool Kit
- Action! Real Math
- Ada
- ALGOL 68
- Amazing Hopper
- AntLang
- APL
- AppleScript
- Applesoft BASIC
- ARM Assembly
- Arturo
- AutoHotkey
- AWK
- BaCon
- BASIC
- BBC BASIC
- BQN
- Bracmat
- C
- C sharp
- C++
- Gnu pbds
- Clojure
- COBOL
- Common Lisp
- Craft Basic
- Crystal
- D
- Delphi
- E
- EasyLang
- EchoLisp
- Elena
- Elixir
- EMal
- Erlang
- ERRE
- Euler Math Toolbox
- Euphoria
- Excel
- F Sharp
- Factor
- Forth
- Fortran
- FreeBASIC
- FutureBasic
- GAP
- Go
- Groovy
- Haskell
- Hstats
- HicEst
- Icon
- Unicon
- J
- Java
- JavaScript
- Jq
- Julia
- K
- Kotlin
- Lambdatalk
- Lasso
- Liberty BASIC
- Lingo
- LiveCode
- LSL
- Lua
- Maple
- Mathematica
- Wolfram Language
- MATLAB
- Maxima
- Min
- MiniScript
- MUMPS
- Nanoquery
- NetRexx
- NewLISP
- Nim
- Oberon-2
- Objeck
- OCaml
- Octave
- OoRexx
- Oz
- PARI/GP
- Pascal
- Perl
- Phix
- Phixmonti
- PHP
- Picat
- PicoLisp
- PL/I
- PowerShell
- Processing
- Prolog
- Pure
- PureBasic
- Python
- R
- Racket
- Raku
- REBOL
- ReScript
- REXX
- Ring
- RPL
- Ruby
- Run BASIC
- Rust
- Scala
- Scheme
- Seed7
- SenseTalk
- Sidef
- Slate
- Smalltalk
- Stata
- Swift
- Tcl
- TI-83 BASIC
- TI-89 BASIC
- Ursala
- Vala
- VBA
- Vedit macro language
- V (Vlang)
- Wortel
- Wren
- Wren-sort
- Wren-math
- Wren-queue
- XPL0
- Yabasic
- Zkl
- Zoea
- Zoea Visual
- Zonnon
- Pages with too many expensive parser function calls