kgl 0.0.6 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 89523b5350ef65694c439eca64804c5c89e2f450cd1b2fcb2fca9eaa466df07b
4
- data.tar.gz: 3c104f76f6ccf3b2283b22162b04ad164076953d9c174e5f54156e96c55de2c0
3
+ metadata.gz: 45157585361c3843ca530c27e06ccf1880d59f61115cd9f8da1ecae34d2fc41e
4
+ data.tar.gz: 2342a753d73994c4a7c725ae18f7247bf7047e347b3c1cec51dfeb83d7ff7449
5
5
  SHA512:
6
- metadata.gz: 706e175a11fc0bcb0d7162e97452d19bbc4a86155d6301fa98d320dd15a98ad52fcfb9dcde08b61caa602d75e25ad27e837cc9246f09b0506fe642878eb530cb
7
- data.tar.gz: f8aa095bd04e2a05d464c72cf22a60eb19637d98342f146e0bffb51c8945314afc9e84bce9406d0286311d6228634f1092c85e480febdd43bd05cca5aeba6c1d
6
+ metadata.gz: 39030c4c9072761a3f658c7d0d8269eedbafd60971db39992fa8712352b01e9cc71ec1ed07b5e51b9544d7119fdaa0025df8c2e86b8f413f52c496bbffa76819
7
+ data.tar.gz: b586b21ff073186953fac8d5c8fa96e5c79150a355e14983188cc6ddca0e388b26efe4a49a95a07a56e2c58f250a3899c14a984e062223119de8e0e106ab8875
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Change Log
2
2
 
3
+ ## 0.0.8 2026/04/15
4
+ - `Rational#approx_reduction(true)` includes only better approximations.
5
+
6
+ ## 0.0.7 2026/04/15
7
+ - Fix missing the alias of `Math.ln` from `Math.log`.
8
+ - Refine `Float#to_r` and `Rational#approx_reduction`.
9
+
3
10
  ## 0.0.6 2026/04/13
4
11
  - Add `Rational#approx_reduction` and refine `Float#to_r` by using this method.
5
12
 
data/README.md CHANGED
@@ -32,10 +32,21 @@ Returns `Rational` value of `self`.
32
32
  Returns exact `Rational` value of `self`, that may not be desirable for usual usage.
33
33
  For instance, (0.1).to_r_exact returns (3602879701896397/36028797018963968) while (0.1).to_r returns (1/10).
34
34
 
35
- ### `Rational#approx_reduction(dig=8, depth=16, org=self)`
36
- Returns aprroximately same as `org` `Rational` value with smaller denominator.
37
- This method search for changing numerator and denominator of `self` by within `1<<dig`.
38
- `depth` is the maximum recursive depth of this method.
35
+ ### `Rational#approx_reduction(all=false)`
36
+ Without the following conditions, this returns `Rational` approximation of `self` with smaller denominator, by using Stern-Brocot tree.
37
+ If `all` is true, this returns an `Array` includes all the path to `self` of the Stern-Brocot tree.
38
+
39
+ When `self==(0/1)` and `all` is false, this returns `self`.
40
+
41
+ When `self==(0/1)` and `all` is true, this returns a pair of negative and positive `Rational` with least denominator which is converted to `0.0` by `Rational#to_f`. For IEEE 754 compliant environments, the value would be -/+ `Rational(1, (((1<<67)-0x4008)<<1008))`.
42
+
43
+ When `self.denominator==1` and `all` is false, this returns a `Rational` value with least absolute numerator which is converted to `self.to_f` by `Rational#to_f`.
44
+
45
+ When `self.denominator==1` and `all` is true, this returns a pair of `Rational`s with least and greatest numerator which are converted to `self.to_f` by `Rational#to_f`.
46
+
47
+ When `self.numerator.abs==1` and `all` is false, this returns a `Rational` value with least denominator which is converted to `selft.to_f` by `Rational#to_f`.
48
+
49
+ When `self.numerator.abs==1` and `all` is true, this returns a pair of `Rational`s with least and greatest denominator which are converted to `self.to_f` by `Rational#to_f`.
39
50
 
40
51
  ### `Integer#to_msm(fps=59.94)`
41
52
  Returns `"[minutes]:[seconds].[milliseconds]"` which corresponds to `self` frames.
data/lib/kgl/kmath.rb CHANGED
@@ -1,84 +1,162 @@
1
+ class << Math
2
+ alias ln log
3
+ end
1
4
  module Math
2
5
  alias ln log
3
6
  module_function
4
7
  def log(base, anti_logarithm=base.tap{base=nil})
5
8
  if base.nil?
6
- ln(angi_logarithm)
9
+ ln(anti_logarithm)
7
10
  else
8
11
  ln(anti_logarithm).quo(ln(base))
9
12
  end
10
13
  end
11
14
  def lg(anti_logarithm)
12
- log(2, anti_logarithm)
15
+ log(2.0, anti_logarithm)
13
16
  end
14
17
  end
15
18
 
16
19
  class Rational
17
- protected def kglsize
18
- [self.numerator.abs, self.denominator].min
19
- end
20
- protected def kgldiff(other)
21
- (self-other).abs
22
- end
23
- def approx_reduction(dig=8, depth=16, org=self)
24
- return self if depth <= 0
25
- self.to_f rescue return self
26
- ret, app = self, self
27
- if (1<<(dig*2)) < self.kglsize
28
- 1.upto(1<<dig) do |i|
29
- [[0, i], [0, -i], [i, 0], [-i, 0]].each do |n, d|
30
- q = Rational(numerator+n, denominator+d)
31
- if q.kglsize < ret.kglsize
32
- if q.kgldiff(org) <= ret.kgldiff(org)
33
- ret = q
34
- elsif q.kglsize < app.kglsize
35
- app = q
36
- end
37
- end
38
- end
39
- 1.upto(i) do |j|
40
- [[j, i], [j, -i], [-j, i], [-j, -i]].each do |a, b|
41
- q = Rational(numerator+a, denominator+b)
42
- if q.kglsize < ret.kglsize
43
- if q.kgldiff(org) <= ret.kgldiff(org)
44
- ret = q
45
- elsif q.kglsize < app.kglsize
46
- app = q
47
- end
48
- end
49
- q = Rational(numerator+b, denominator+a)
50
- if q.kglsize < ret.kglsize
51
- if q.kgldiff(org) <= ret.kgldiff(org)
52
- ret = q
53
- elsif q.kglsize < app.kglsize
54
- app = q
55
- end
56
- end
57
- end
20
+ def approx_reduction(all=false)
21
+ if self.numerator == 0
22
+ return self unless all
23
+ d = 0
24
+ d += 1 while Rational(1, 1<<d).to_f != 0.0
25
+ n = 1<<d
26
+ (d-1).downto(0) do |i|
27
+ e = (1<<i)
28
+ n -= e if Rational(1, n-e).to_f == 0.0
29
+ end
30
+ return [Rational(-1, n), Rational(1, n)]
31
+ elsif self.denominator == 1
32
+ s = self < 0 ? -1 : 1
33
+ d, n = 0, self.numerator.abs
34
+ f = n.to_f
35
+ d += 1 while (n-(1<<d)).to_f == f
36
+ (d-1).downto(0) do |i|
37
+ e = (1<<i)
38
+ n -= e if (n-e).to_f == f
39
+ end
40
+ r = Rational(n*s, 1)
41
+ return r unless all
42
+ d, n = 0, self.numerator.abs
43
+ d += 1 while (n+(1<<d)).to_f == f
44
+ (d-1).downto(0) do |i|
45
+ e = (1<<i)
46
+ n += e if (n+e).to_f == f
47
+ end
48
+ if n == r.numerator.abs
49
+ return [r]
50
+ else
51
+ return [r, Rational(n*s, 1)]
52
+ end
53
+ elsif self.numerator.abs == 1
54
+ d, n = 0, self.denominator
55
+ f = self.to_f.abs
56
+ if f == 0.0
57
+ unless all
58
+ return Rational(0, 1).approx_reduction(true)[self.numerator<0 ? 0 : 1]
59
+ else
60
+ return Rational(0, 1).approx_reduction(true)
58
61
  end
59
62
  end
60
- end
61
- if ret.kglsize < self.kglsize
62
- ret.approx_reduction(dig, depth-1, org)
63
+ d += 1 while Rational(1, n-(1<<d)).to_f == f
64
+ (d-1).downto(0) do |i|
65
+ e = (1<<i)
66
+ n -= e if Rational(1, n-e).to_f == f
67
+ end
68
+ r = Rational(self.numerator, n)
69
+ return r unless all
70
+ d, n = 0, self.denominator
71
+ d += 1 while Rational(1, n+(1<<d)).to_f == f
72
+ (d-1).downto(0) do |i|
73
+ e = (1<<i)
74
+ n += e if Rational(1, n+e).to_f == f
75
+ end
76
+ if n == r.denominator
77
+ return [r]
78
+ else
79
+ return [r, Rational(self.numerator, n)]
80
+ end
63
81
  else
64
- app.approx_reduction(dig, depth-1, org)
82
+ s = self < 0 ? -1 : 1
83
+ q = self.abs
84
+ if q.denominator < q.numerator
85
+ l = [q.numerator.div(q.denominator), 1]
86
+ h = [l[0]+1, 1]
87
+ else
88
+ h = [1, q.denominator.div(q.numerator)]
89
+ l = [1, h[1]+1]
90
+ end
91
+ res = [Rational(*l)]
92
+ r = Rational(*h)
93
+ foo, bar = (r-q).abs, (res[0]-q).abs
94
+ res = [r] if foo < bar || ( foo == bar && h.min < l.min )
95
+ i = 0
96
+ loop do
97
+ m = [l[0]+h[0], l[1]+h[1]]
98
+ r = Rational(*m)
99
+ if q.denominator <= r.denominator
100
+ return all ? res : res[-1]
101
+ elsif r < q
102
+ l = m
103
+ else
104
+ h = m
105
+ end
106
+ res << r*s if (r-q).abs < (res[-1]-q).abs
107
+ end
65
108
  end
66
109
  end
67
110
  end
68
111
 
69
112
  class Float
70
- def to_r(th=8)
71
- r = self.to_r_exact
72
- q = r.approx_reduction
73
- q.to_f == self ? q : r
113
+ if method_defined?(:to_r)
114
+ alias to_r_exact to_r
115
+ else
116
+ def to_r_exact
117
+ raise FloatDomainError, self.inspect unless self.finite?
118
+ if RADIX == 2
119
+ md = MANT_DIG
120
+ else
121
+ md = (MANT_DIG*Math.lg(RADIX)).floor
122
+ end
123
+ s, e = Math.frexp(self)
124
+ if e < md
125
+ Rational(Math.ldexp(s, md).to_i, 1<<(md-e))
126
+ else
127
+ Rational(self.to_i, 1)
128
+ end
129
+ end
74
130
  end
75
- def to_r_exact
76
- raise FloatDomainError, self.inspect unless self.finite?
77
- s, e = Math.frexp(self)
78
- if e < MANT_DIG
79
- Rational(Math.ldexp(s, MANT_DIG).to_i, 1<<(MANT_DIG-e))
131
+ def to_r
132
+ a = self.abs
133
+ q = a.to_r_exact
134
+ s = (self < 0.0) ? -1 : 1
135
+ if q.denominator < q.numerator
136
+ l = [q.numerator.div(q.denominator), 1]
137
+ r = Rational(*l)
138
+ return r*s if r.to_f == a
139
+ h = [l[0]+1, 1]
140
+ r = Rational(*h)
141
+ return r*s if r.to_f == a
80
142
  else
81
- Rational(self.to_i, 1)
143
+ h = [1, q.denominator.div(q.numerator)]
144
+ r = Rational(*h)
145
+ return r*s if r.to_f == a
146
+ l = [1, h[1]+1]
147
+ r = Rational(*l)
148
+ return r*s if r.to_f == a
149
+ end
150
+ loop do
151
+ m = [l[0]+h[0], l[1]+h[1]]
152
+ r = Rational(*m)
153
+ if r.to_f == a
154
+ return r*s
155
+ elsif r < q
156
+ l = m
157
+ else
158
+ h = m
159
+ end
82
160
  end
83
161
  end
84
162
  end
data/lib/kgl/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Kgl
2
- VERSION = '0.0.6'
2
+ VERSION = '0.0.8'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kgl
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - KAZOON