#四捨五入率後割合百パーセント超え
下記のように、割合はすべて、16.666の場合、
levelList = new List<double>() { 16.666, 16.666, 16.666, 16.666, 16.666, 16.666 };
{16.7、16.7、16.7、16.7、16.7、16.7} 四捨五入率後割合合計100%超えちゃいます。
リストが四捨五入率後割合合計100%になる方法を調べました。
最大端数と最小端数のindexを算出、最大端数が0.1になるまで最小端数を移動というやり方で成功しました
#例
###数列:16.666 , 16.666 , 16.666 , 16.666 , 16.666 , 16.666
.初期四捨五入数列:16.7 , 16.7 , 16.7 , 16.7 , 16.7 , 16.7 sum=100.2
.初期端数:-0.0333333333333 , -0.0333333333333 , -0.0333333333333 , -0.0333333333333 , -0.0333333333333 , -0.0333333333333
LOOP1回目
hasu_temp1:-0.0333333333333 , -0.0333333333333 , -0.0333333333333 , -0.0333333333333 , -0.0333333333333 , -0.0333333333333
1番目最小端数:[-0.0333333333333] 1番目最大端数:[-0.0333333333333]
B 端数すべて同じ max<0 minindex数-add add:0.0666666666667
-> 移動後:-0.1000000000000 , -0.0333333333333 , -0.0333333333333 , -0.0333333333333 , -0.0333333333333 , -0.0333333333333
端数を試し計上:16.6 , 16.7 , 16.7 , 16.7 , 16.7 , 16.7 sum=100.1
LOOP2回目
hasu_temp2:-0.0333333333333 , -0.0333333333333 , -0.0333333333333 , -0.0333333333333 , -0.0333333333333
2番目最小端数:[-0.0333333333333] 2番目最大端数:[-0.0333333333333]
B 端数すべて同じ max<0 minindex数-add add:0.0666666666667
-> 移動後:-0.1000000000000 , -0.1000000000000 , -0.0333333333333 , -0.0333333333333 , -0.0333333333333 , -0.0333333333333
端数を試し計上:16.6 , 16.6 , 16.7 , 16.7 , 16.7 , 16.7 sum=100.0
###結果:16.6 , 16.6 , 16.7 , 16.7 , 16.7 , 16.7 sum=100.0
###数列:33.333 , 33.333 , 33.333
.初期四捨五入数列:33.3 , 33.3 , 33.3 sum=99.9
.初期端数:0.0333333333333 , 0.0333333333333 , 0.0333333333333
LOOP1回目
hasu_temp1:0.0333333333333 , 0.0333333333333 , 0.0333333333333
1番目最小端数:[0.0333333333333] 1番目最大端数:[0.0333333333333]
C 端数すべて同じ max>=0 minindex数+add add:0.0666666666667
-> 移動後:0.1000000000000 , 0.0333333333333 , 0.0333333333333
端数を試し計上:33.4 , 33.3 , 33.3 sum=100.0
###結果:33.4 , 33.3 , 33.3 sum=100.0
###数列:33.3 , 33.3 , 33.3 , 0.1
.初期四捨五入数列:33.3 , 33.3 , 33.3 , 0.1 sum=100.0
.初期端数:0.0 , 0.0 , 0.0 , 0.0
###結果:33.3 , 33.3 , 33.3 , 0.1 sum=100.0
###数列:33.3 , 33.3 , 33.3 , 99.999
.初期四捨五入数列:16.7 , 16.7 , 16.7 , 50.0 sum=100.1
.初期端数:-0.0415875016884 , -0.0415875016884 , -0.0415875016884 , 0.0247625050651
LOOP1回目
hasu_temp1:-0.0415875016884 , -0.0415875016884 , -0.0415875016884 , 0.0247625050651
1番目最小端数:[-0.0415875016884] 4番目最大端数:[0.0247625050651]
A maxindex != minindex 各自maxindex数+add,minindex数-add add:-0.0415875016884
-> 移動後:0.0000000000000 , -0.0415875016884 , -0.0415875016884 , -0.0168249966233
LOOP2回目
hasu_temp2:-0.0415875016884 , -0.0415875016884 , -0.0168249966233
2番目最小端数:[-0.0415875016884] 4番目最大端数:[-0.0168249966233]
A maxindex != minindex 各自maxindex数+add,minindex数-add add:-0.0415875016884
-> 移動後:0.0000000000000 , 0.0000000000000 , -0.0415875016884 , -0.0584124983117
LOOP3回目
hasu_temp3:-0.0415875016884 , -0.0584124983117
4番目最小端数:[-0.0584124983117] 3番目最大端数:[-0.0415875016884]
A maxindex != minindex 各自maxindex数+add,minindex数-add add:-0.0584124983117
-> 移動後:0.0000000000000 , 0.0000000000000 , -0.1000000000001 , 0.0000000000000
LOOP4回目
hasu_temp4:-0.1000000000001
3番目最小端数:[-0.1000000000001] 3番目最大端数:[-0.1000000000001]
B 端数すべて同じ max<0 minindex数-add add:-0.0000000000001
-> 移動後:0.0000000000000 , 0.0000000000000 , -0.1000000000000 , 0.0000000000000
端数を試し計上:16.7 , 16.7 , 16.6 , 50.0 sum=100.0
###結果:16.7 , 16.7 , 16.6 , 50.0 sum=100.0
/// <summary>
/// 割合100%取得
/// 四捨五入率を合計すると100%になる方法
/// </summary>
/// <param name="resultList"></param>
/// <returns></returns>
public static List<decimal> GetPercent100(List<double> levelList)
{
var total = levelList.Sum();
var loop_i=1;//計算loop回数
// 配列
List<decimal> result_temp = levelList.Select(x=>Convert.ToDecimal( x* 100 / total)).ToList();
List<decimal> result = result_temp.Select(x=>Math.Round(x, 1, MidpointRounding.AwayFromZero)).ToList();
Console.WriteLine(".初期四捨五入数列:" + string.Join(" , ", result) + " sum=" + result.Sum());
List<decimal> result_hasu = result_temp.Zip(result, (t1, t2) => t1 - t2).ToList();
Console.WriteLine(".初期端数:" + string.Join(" , ", result_hasu));
if (result.Sum() == 100) { return result; }
do
{
// 最大端数と最小端数のindexを算出
var result_hasu_temp = result_hasu.Where(i => !(i == 0 || i==Convert.ToDecimal( 0.1 ) || i==Convert.ToDecimal(-0.1))).ToList();
decimal cnt_hasu = result_hasu_temp.Count();
decimal max = result_hasu_temp.Max();
decimal min = result_hasu_temp.Min();
int maxindex = result_hasu.FindIndex(i => i.CompareTo(max)==0);
int minindex = result_hasu.FindIndex(i => i == min);
Console.WriteLine(" LOOP" +loop_i+"回目");
Console.WriteLine(" hasu_temp"+loop_i+":" + string.Join(" , ", result_hasu_temp));
if (maxindex != -1)
{
Console.WriteLine(" "+(minindex+1)+"番目最小端数:["+min+"] "+(maxindex+1)+"番目最大端数:[" +max+"] ");
if ((minindex != -1 && maxindex != minindex))
{
// 最大端数、最小端数の項目は違う
// 0.1までの最小調整端数を算出し、最大端数は調整端数を足す、最小端数は調整端数を引く
var add = Math.Min((decimal)0.1 - result_hasu[maxindex], result_hasu[minindex]);
result_hasu[maxindex] += add;
result_hasu[minindex] -= add;
Console.WriteLine(" A maxindex != minindex 各自maxindex数+add,minindex数-add add:"+add);
Console.WriteLine(" -> 移動後:" + string.Join(" , ", result_hasu));
}
else if (result_hasu_temp.Average()==max&&result_hasu_temp.Average() ==min
&& maxindex == minindex)
{
//端数すべて同じ
// 最大端数が0.1になるまで最小端数を移動
if (max<0)
{
//端数<0の場合
var add = (decimal)0.1 - Math.Abs(result_hasu[maxindex]);
result_hasu[minindex] -= add;
Console.WriteLine(" B 端数すべて同じ max<0 minindex数-add add:"+add);
}
else
{
//端数>=0の場合
var add = (decimal)0.1 - Math.Abs(result_hasu[maxindex]);
result_hasu[maxindex] += add;
Console.WriteLine(" C 端数すべて同じ max>=0 minindex数+add add:"+add);
}
Console.WriteLine(" -> 移動後:" + string.Join(" , ", result_hasu));
// 端数を結果に試し計上
var t3 = result.Zip(result_hasu, (t1, t2) => Math.Round(t1 + Math.Round(t2, 1, MidpointRounding.AwayFromZero), 1, MidpointRounding.AwayFromZero)).ToList();
Console.WriteLine(" 端数を試し計上:" + string.Join(" , ", t3) + " sum=" + t3.Sum());
if (t3.Sum() == 100)
{
break;
}
}
else
{
Console.WriteLine(" ★D★");
break;
}
}
loop_i++;
} while (true);
// 端数を結果に戻す
result = result.Zip(result_hasu, (t1, t2) => Math.Round( t1 + Math.Round(t2, 1, MidpointRounding.AwayFromZero), 1, MidpointRounding.AwayFromZero)).ToList();
return result;
}