簡體   English   中英

在C ++中獲得中等價值

[英]Get mid value in C++

考慮三個值x, y, z

得到中間值(不是平均值,而是既不是min也不是max )的公式是什么?

const double min = std::min(x, std::min(y, z));
const double mid = /* what formula here ? */
const double max = std::max(x, std::max(y, z));

以對稱方式一次找到所有三個:

min = x; med = y; max = z;

if (min > med) std::swap(min, med);
if (med > max) std::swap(med, max);
if (min > med) std::swap(min, med);

這似乎在作弊,但是: x + y + z - min - max

鏈接的答案在評論中共享:

const double mid = std::max(std::min(x,y),std::min(std::max(x,y),z));

編輯 -正如艾倫所指出的,我錯過了一個案子。 我現在給出了更直觀的證明。

直接證明 :關於x和y不失一般性。
從最里面的表達式開始, min(max(x,y),z) ...

  1. 如果返回z ,則關系為: max(x,y)> z 然后,表達式的計算結果為max(min(x,y),z) 通過這一點,我們能夠確定min(x,y)與z之間的關系。
    如果min(x,y)> z ,則z均小於x和y(因為關系變為: max(x,y)> min(x,y)> z )。 因此,min(x,y)確實是中位數,而max(min(x,y),z)返回該中位數。
    如果min(x,y)<z ,則z實際上是中位數(因為min(x,y)<z <max(x,y) )。

  2. 如果返回x ,則我們有x <zy <z 表達式的計算結果為: max(min(x,y),x) 由於max(x,y)評估為x,因此min(x,y)評估為y。 得到關系z> x> y 我們返回x和y的最大值(隨着表達式變為max(y,x) ),它是x也是中位數。 (請注意,y的證明是對稱的)

證明結束


舊證明-注意它不完整 (直接):

不失一般性:假設x> y> z
x和y的最小值為y。 (x和y的最大值)和z的最小值是z。
y和z的最大值為y,即中位數。

假設x = y> z
x和y的最小值表示為x。 最小值(x和y的最大值是x)和z是z。
以上兩個的最大值是x,這是中位數。

假設x> y = z
x和y的最小值為y。 最小值(x和y的最大值是x)和z是z。
上述兩個的最大值是y,即中位數。

最后,假設x = y = z
這三個數字中的任何一個都是中位數。並且使用的公式將返回某個數字。

它比Alan的技巧丑陋一些,但它不會導致溢出或數值錯誤,等等:

int x, y, z, median;
...

if (x <= y && y <= z || y >= z && y <= x) median = y;
else if (y <= x && x <= z || x >= z && x <= y) median = x;
else median = z;

算法很簡單:

  • 檢查x是否在y和z之間,如果是,則是。

  • 檢查y是否在x和z之間,如果是,則是。

  • 由於它既不是x也不是y,因此必須為z。

================================================== ===

如果您具有三個以上的元素,則還可以更靈活地進行排序。

//或xor實現,沒關系...

void myswap(int * a,int * b){int temp = * b; * b = * a; * a =溫度; }

int x, y, z;
// Initialize them
int min = x;
int med = y;
int max = z;

// you could also use std::swap here if it does not have to be C compatible
// In that case, you could just pass the variables without the address operator.
if (min > med) myswap(&min, &med);
if (med > max) myswap(&med, &max);
if (min > med) myswap(&min, &med);

艾倫“騙子”的一種變體,可以防止溢出:

#include <iostream>
#include <algorithm>

using namespace std;
int main(int argc, char *argv[]) {
    double a = 1e308;
    double b = 6e306;
    double c = 7.5e18;

    double mn = min(a,min(b,c));
    double mx = max(a,max(b,c));
    double avg = mn + (mx-mn)*0.5;
    double mid = a - avg + b - avg + c;

    cout << mid << endl;
}

輸出:

6e+306

它利用二進制搜索中經常使用的avg公式來防止溢出:

兩個值的平均值可以計算為low + (high-low)/2

但是,它僅適用於正值。 可能的回退包括Alan的答案,或者對於平均值計算僅是(x+y)/2

請注意,雙精度會在這里起作用,並且可能導致mid計算出現問題。 它對於正整數確實非常有效:)

最好的方法是使用通用中值函數模板。 無需復制,交換或數學運算。

template <typename T>
const T& median(const T& a, const T& b, const T& c)
{
    if (a < b)
        if (b < c)
            return b;
        else if (a < c)
            return c;
        else
            return a;
    else if (a < c)
        return a;
    else if (b < c)
        return c;
    else
        return b;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM