これが別の試みです。は使用しませんsample
が、を使用しますrunif
。合計を示すオプションの「メッセージ」を出力に追加しました。これは、showSum
引数を使用してトリガーできます。Tolerance
ターゲットにどれだけ近いかを指定する引数もあります。
SampleToSum <- function(Target = 100, VecLen = 10,
InRange = 1:100, Tolerance = 2,
showSum = TRUE) {
Res <- vector()
while ( TRUE ) {
Res <- round(diff(c(0, sort(runif(VecLen - 1)), 1)) * Target)
if ( all(Res > 0) &
all(Res >= min(InRange)) &
all(Res <= max(InRange)) &
abs((sum(Res) - Target)) <= Tolerance ) { break }
}
if (isTRUE(showSum)) cat("Total = ", sum(Res), "\n")
Res
}
下記は用例です。
デフォルト設定と設定の違いに注意してくださいTolerance = 0
set.seed(1)
SampleToSum()
# Total = 101
# [1] 20 6 11 20 6 3 24 1 4 6
SampleToSum(Tolerance=0)
# Total = 100
# [1] 19 15 4 10 1 11 7 16 4 13
を使用して、この動作を確認できますreplicate
。Tolerance = 0
関数を5回設定して実行した結果は次のとおりです。
system.time(output <- replicate(5, SampleToSum(
Target = 1376,
VecLen = 13,
InRange = 10:200,
Tolerance = 0)))
# Total = 1376
# Total = 1376
# Total = 1376
# Total = 1376
# Total = 1376
# user system elapsed
# 0.144 0.000 0.145
output
# [,1] [,2] [,3] [,4] [,5]
# [1,] 29 46 11 43 171
# [2,] 103 161 113 195 197
# [3,] 145 134 91 131 147
# [4,] 154 173 138 19 17
# [5,] 197 62 173 11 87
# [6,] 101 142 87 173 99
# [7,] 168 61 97 40 121
# [8,] 140 121 99 135 117
# [9,] 46 78 31 200 79
# [10,] 140 168 146 17 56
# [11,] 21 146 117 182 85
# [12,] 63 30 180 179 78
# [13,] 69 54 93 51 122
Tolerance = 5
また、機能を5回設定して実行する場合も同様です。
system.time(output <- replicate(5, SampleToSum(
Target = 1376,
VecLen = 13,
InRange = 10:200,
Tolerance = 5)))
# Total = 1375
# Total = 1376
# Total = 1374
# Total = 1374
# Total = 1376
# user system elapsed
# 0.060 0.000 0.058
output
# [,1] [,2] [,3] [,4] [,5]
# [1,] 65 190 103 15 47
# [2,] 160 95 98 196 183
# [3,] 178 169 134 15 26
# [4,] 49 53 186 48 41
# [5,] 104 81 161 171 180
# [6,] 54 126 67 130 182
# [7,] 34 131 49 113 76
# [8,] 17 21 107 62 95
# [9,] 151 136 132 195 169
# [10,] 194 187 91 163 22
# [11,] 23 69 54 97 30
# [12,] 190 14 134 43 150
# [13,] 156 104 58 126 175
当然のことながら、許容値を0に設定すると、関数が遅くなります。
速度(またはその欠如)
これは「ランダムな」プロセスであるため、数字の正しい組み合わせを見つけるのにかかる時間を推測するのは難しいことに注意してください。たとえば、を使用してset.seed(123)
、次のテストを3回続けて実行しました。
system.time(SampleToSum(Target = 1163,
VecLen = 15,
InRange = 50:150))
最初の実行には9秒強かかりました。1秒は7.5秒強かかりました。3番目は...381秒弱でした!それはたくさんのバリエーションです!
好奇心から、関数にカウンターを追加しました。最初の実行では、55026回試行して、すべての条件を満たすベクトルに到達しました。(私は2回目と3回目の試みをわざわざ試みませんでした。)
入力が妥当であることを確認するために、関数にエラーまたは健全性チェックを追加するとよい場合があります。たとえば、SampleToSum(Target = 100, VecLen = 10, InRange = 15:50)
15から50の範囲では、100に到達する方法がなく、ベクトルに10の値があるため、入力できないはずです。