1 #Region "Microsoft.VisualBasic::4dc58ec87bf71221dcd6afe624e304dd, Microsoft.VisualBasic.Core\Extensions\Math\Random\PreciseRandom.vb"
2
3     ' Author:
4     
5     '       asuka (amethyst.asuka@gcmodeller.org)
6     '       xie (genetics@smrucc.org)
7     '       xieguigang (xie.guigang@live.com)
8     
9     ' Copyright (c) 2018 GPL3 Licensed
10     
11     
12     ' GNU GENERAL PUBLIC LICENSE (GPL3)
13     
14     
15     ' This program is free software: you can redistribute it and/or modify
16     ' it under the terms of the GNU General Public License as published by
17     ' the Free Software Foundation, either version 3 of the License, or
18     ' (at your option) any later version.
19     
20     ' This program is distributed in the hope that it will be useful,
21     ' but WITHOUT ANY WARRANTY; without even the implied warranty of
22     ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23     ' GNU General Public License for more details.
24     
25     ' You should have received a copy of the GNU General Public License
26     ' along with this program. If not, see <http://www.gnu.org/licenses/>.
27
28
29
30     ' /********************************************************************************/
31
32     ' Summaries:
33
34     '     Class PreciseRandom
35     
36     '         Constructor: (+2 OverloadsSub New
37     '         FunctionNextDouble, NextNumber, rand, ToString
38     
39     
40     ' /********************************************************************************/
41
42 #End Region
43
44 Imports Microsoft.VisualBasic.ComponentModel.Ranges.Model
45 Imports Microsoft.VisualBasic.Serialization.JSON
46 Imports sys = System.Math
47
48 Namespace Math
49
50     ''' <summary>
51     ''' 主要针对的是非常小的小数(仅适用于Positive Number)
52     ''' </summary>
53     Public Class PreciseRandom
54
55         ReadOnly __rnd As Random
56         ReadOnly __digits As DoubleRange
57
58         ''' <summary>
59         ''' 4.94065645841247E-324
60         ''' </summary>
61         Public Const Epsilon As Double = Double.Epsilon
62
63         ''' <summary>
64         ''' 最小的精度为``<see cref="System.Double.Epsilon"/>=4.94065645841247E-324``
65         ''' </summary>
66         ''' <param name="digitMin">``10^?``</param>
67         ''' <param name="digitMax">``10^?``</param>
68         Sub New(digitMin!, digitMax!, Optional seeds As IRandomSeeds = Nothing)
69             ' 假若max是1e10的话,则最高的位数是10,
70             ' 这时候由于计算公式的原因最多只能够到9所以在这里需要手动添加一来避免这个问题
71             __digits = New DoubleRange(digitMin, digitMax + 1)
72
73             If seeds Is Nothing Then
74                 __rnd = New Random
75             Else
76                 __rnd = seeds()
77             End If
78         End Sub
79
80         ''' <summary>
81         ''' 
82         ''' </summary>
83         ''' <param name="from">最小的精度为<see cref="System.Double.Epsilon"/></param>
84         ''' <param name="[to]"></param>
85         Sub New(from#, to#, Optional seeds As IRandomSeeds = Nothing)
86             Call Me.New(
87                 CSng(If(from = 0R, 0F, sys.Log10(from))), ' 避免出现log(0)的情况
88                 CSng(If([to] = 0R, 0F, sys.Log10([to]))),
89                 seeds)
90         End Sub
91
92         Public Overrides Function ToString() As String
93             Return __digits.GetJson & " --> " & NextNumber()
94         End Function
95
96         Private Function rand() As Double
97             SyncLock __rnd  ' 线程不安全,所以需要加锁,不然无法得到随机数
98                 ' 因为多线程的时候不加锁在不同的线程之间同时调用会得到相同的数
99                 Return __rnd.NextDouble
100             End SyncLock
101         End Function
102
103         ''' <summary>
104         ''' 获取一个在给定的小数位范围内的随机的数
105         ''' </summary>
106         ''' <returns></returns>
107         Public Function NextNumber() As Double
108             Dim d% = rand() * __digits.Length + __digits.Min      ' generates the digits
109             Dim digits# = 10 ^ d
110             Dim r# = rand()
111             Return r * digits
112         End Function
113
114         ''' <summary>
115         ''' 这个方法可能只适用于很小的数,例如1e-100到1e-10这样子的
116         ''' </summary>
117         ''' <param name="range"></param>
118         ''' <returns></returns>
119         Public Function NextDouble(range As DoubleRange) As Double
120             Return range.Min + range.Length * NextNumber()
121         End Function
122     End Class
123 End Namespace