博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
实现求n个随机数和为sum的haskell程序
阅读量:5284 次
发布时间:2019-06-14

本文共 2218 字,大约阅读时间需要 7 分钟。

近日看到这篇博客,写一个程序:生成26个非负随机数,要求其和是301。最近对Haskell很感兴趣,就试着写了一下,不动手则已,真写起来还是遇到点问题。在函数式编程里每个确定的输入一定会有确定的输出,而随机数就意味着相同的程序每次运行就输出不同的结果。

一开始完成的代码如下,不算import,实际就3行代码:

import System.Random
-- haskell的算法大量采用递归,如果只有一个数,要求其和为sum,那么这个列表当然就是[sum]了f 1 sum =[sum]
 
-- 对于n个数时,就是随机选一个范围在0到sum之前的数m,然后再与(n-1)个随机数(要求其和为sum-m)合在一起即可f n sum = m : (f (n-1) (sum-m))        where m = randomRIO (0,sum)

但编译出现问题,因为代码用到了IO,纯函数和带IO的函数放在一起有问题,想了许多办法也解决不了,无奈想到了stackoverflow,注册账号后把发到stackoverflow网站上,没想到高手真多,不出几个小时问题就搞定了,正确代码如下:

f 1 sum = return [sum]f n sum = do  x  <- randomRIO (0, sum)  xs <- f (n -1) (sum - x)  return (x : xs)

几个运行结果

[215,33,6,12,7,1,4,4,15,3,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]

[284,1,1,13,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]

[297,3,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]

 

更有高手发现这种算法会出现大串的0,想出了下面的改进算法(原来与博客园上的算法一是一样的):

假设要得到4个随机数,和为100

1)取3个随机数,例如[72,33,43]

2)前后分别插入0,100,排序,得到 [0,33,43,72,100]

3)计算相邻2个数的差值 [33-0, 43-33, 72-43, 100-72]

结果就出来了 [33,10,29,28],分布比原来的算法好多了。

[0,17,1,19,35,1,4,11,29,2,12,1,6,6,47,1,18,25,1,11,1,2,2,20,2,27]

[0,1,14,11,7,16,4,5,40,14,4,2,14,16,31,2,3,5,1,18,26,17,1,28,0,21]

[15,2,1,28,2,15,6,18,0,19,12,3,7,17,33,23,41,4,2,2,10,0,2,3,32,4]

 

英文原文如下:

As others have pointed out, your algorithm will not give uniformly-distributed output.

An easy way to get uniform output is:

  • Generate n-1 random numbers in the range from 0 to sum (inclusive)
  • Insert 0 and sum into the list of random numbers
  • Sort the resulting list
  • Return the list of differences between consecutive values in the sorted list

Example:

  • Suppose we want four integers with a sum of 100, we request three random values from the RNG and it gives us [72,33,43]
  • We insert 0 and 100 and sort the list, giving [0,33,43,72,100]
  • We compute the differences [33-0, 43-33, 72-43, 100-72]
  • The result would be [33,10,29,28]

In Haskell:

import System.Randomimport Data.ListrandomsWithSum :: (Num n, Ord n, Random n) => Int -> n -> IO [n]randomsWithSum len sum =    do b <- sequence $ take (len-1) $ repeat $ randomRIO (0,sum)       let sb = sort (sum:b) in           return $ zipWith (-) sb (0:sb)

For your example you would call this as randomsWithSum 26 (301::Int)

转载于:https://www.cnblogs.com/speeding/archive/2012/11/04/2754313.html

你可能感兴趣的文章
记叙在人生路上对你影响最大的三位老师
查看>>
002.大数据第二天
查看>>
python装饰器
查看>>
树上的路径
查看>>
问题总结
查看>>
软件随笔
查看>>
Linux下SVN自动更新web [转]
查看>>
Openstack api 学习文档 & restclient使用文档
查看>>
poj100纪念
查看>>
NetWork——关于TCP协议的三次握手和四次挥手
查看>>
An easy problem
查看>>
MauiMETA工具的使用(一)
查看>>
LeetCode: Anagrams 解题报告
查看>>
Qt 中获取本机IP地址
查看>>
070102_赌博设计:概率的基本概念,古典概型
查看>>
IT人生的价值和意义 感觉真的有了
查看>>
JS DOM对象
查看>>
OGR – Merging Multiple SHP files
查看>>
创业公司该不该被收购?(转)
查看>>
sqlserver 行转列、列转行[转]
查看>>