1
1

More than 3 years have passed since last update.

四捨五入後 割合率合計100%になる方法

Last updated at Posted at 2021-06-25

四捨五入率後割合百パーセント超え

下記のように、割合はすべて、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;
        }
1
1
5

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1