line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# Copyright 2012, 2013, 2014 Kevin Ryde |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
# This file is part of Math-NumSeq. |
4
|
|
|
|
|
|
|
# |
5
|
|
|
|
|
|
|
# Math-NumSeq is free software; you can redistribute it and/or modify |
6
|
|
|
|
|
|
|
# it under the terms of the GNU General Public License as published by the |
7
|
|
|
|
|
|
|
# Free Software Foundation; either version 3, or (at your option) any later |
8
|
|
|
|
|
|
|
# version. |
9
|
|
|
|
|
|
|
# |
10
|
|
|
|
|
|
|
# Math-NumSeq is distributed in the hope that it will be useful, but |
11
|
|
|
|
|
|
|
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
12
|
|
|
|
|
|
|
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
13
|
|
|
|
|
|
|
# for more details. |
14
|
|
|
|
|
|
|
# |
15
|
|
|
|
|
|
|
# You should have received a copy of the GNU General Public License along |
16
|
|
|
|
|
|
|
# with Math-NumSeq. If not, see . |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
# http://www.iki.fi/~kartturi/matikka/tab9766.htm |
20
|
|
|
|
|
|
|
# A009766 Catalan triangle |
21
|
|
|
|
|
|
|
# A099039 Riordan array |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
package Math::NumSeq::BalancedBinary; |
24
|
2
|
|
|
2
|
|
7446
|
use 5.004; |
|
2
|
|
|
|
|
7
|
|
25
|
2
|
|
|
2
|
|
9
|
use strict; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
43
|
|
26
|
2
|
|
|
2
|
|
6
|
use List::Util 'max'; |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
135
|
|
27
|
|
|
|
|
|
|
|
28
|
2
|
|
|
2
|
|
7
|
use vars '$VERSION', '@ISA'; |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
96
|
|
29
|
|
|
|
|
|
|
$VERSION = 72; |
30
|
|
|
|
|
|
|
|
31
|
2
|
|
|
2
|
|
386
|
use Math::NumSeq; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
79
|
|
32
|
|
|
|
|
|
|
@ISA = ('Math::NumSeq'); |
33
|
|
|
|
|
|
|
*_is_infinite = \&Math::NumSeq::_is_infinite; |
34
|
|
|
|
|
|
|
*_to_bigint = \&Math::NumSeq::_to_bigint; |
35
|
|
|
|
|
|
|
|
36
|
2
|
|
|
2
|
|
327
|
use Math::NumSeq::Repdigits; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
112
|
|
37
|
|
|
|
|
|
|
*_digit_split_lowtohigh = \&Math::NumSeq::Repdigits::_digit_split_lowtohigh; |
38
|
|
|
|
|
|
|
|
39
|
2
|
|
|
2
|
|
349
|
use Math::NumSeq::Fibonacci; |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
69
|
|
40
|
|
|
|
|
|
|
*_blog2_estimate = \&Math::NumSeq::Fibonacci::_blog2_estimate; |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
# uncomment this to run the ### lines |
43
|
|
|
|
|
|
|
# use Smart::Comments; |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
# use constant name => Math::NumSeq::__('Balanced Binary'); |
47
|
2
|
|
|
2
|
|
7
|
use constant description => Math::NumSeq::__('Bits 1,0 balanced like parentheses.'); |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
5
|
|
48
|
2
|
|
|
2
|
|
6
|
use constant characteristic_increasing => 1; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
67
|
|
49
|
2
|
|
|
2
|
|
5
|
use constant characteristic_integer => 1; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
68
|
|
50
|
2
|
|
|
2
|
|
5
|
use constant default_i_start => 1; |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
76
|
|
51
|
2
|
|
|
2
|
|
9
|
use constant values_min => 2; |
|
2
|
|
|
|
|
10
|
|
|
2
|
|
|
|
|
339
|
|
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
# pred() works, next() doesn't. |
54
|
|
|
|
|
|
|
# Any merit in bit-reversed form ? |
55
|
|
|
|
|
|
|
# |
56
|
|
|
|
|
|
|
# use constant parameter_info_array => |
57
|
|
|
|
|
|
|
# [ { name => 'direction', |
58
|
|
|
|
|
|
|
# share_key => 'pairs_fsb', |
59
|
|
|
|
|
|
|
# display => Math::NumSeq::__('Direction'), |
60
|
|
|
|
|
|
|
# type => 'enum', |
61
|
|
|
|
|
|
|
# default => 'HtoL', |
62
|
|
|
|
|
|
|
# choices => ['HtoL','LtoH'], |
63
|
|
|
|
|
|
|
# choices_display => [Math::NumSeq::__('HtoL'), |
64
|
|
|
|
|
|
|
# Math::NumSeq::__('LtoH'), |
65
|
|
|
|
|
|
|
# ], |
66
|
|
|
|
|
|
|
# }, |
67
|
|
|
|
|
|
|
# ]; |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
sub new { |
70
|
4
|
|
|
4
|
1
|
1861
|
my $self = shift->SUPER::new(@_); |
71
|
4
|
|
50
|
|
|
20
|
$self->{'direction'} ||= 'HtoL'; |
72
|
4
|
|
|
|
|
7
|
return $self; |
73
|
|
|
|
|
|
|
} |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
#------------------------------------------------------------------------------ |
76
|
|
|
|
|
|
|
# A063171 same in binary |
77
|
|
|
|
|
|
|
# A080116 predicate 0,1 |
78
|
|
|
|
|
|
|
# A080300 inverse, ranking value->i or 0 |
79
|
|
|
|
|
|
|
# A080237 num trailing zeros |
80
|
|
|
|
|
|
|
# A085192 first diffs |
81
|
|
|
|
|
|
|
# A000108 Catalan numbers, count of values in 4^k blocks |
82
|
|
|
|
|
|
|
# A071152 balanced/2, Lukasiewicz words for the rooted plane binary trees |
83
|
|
|
|
|
|
|
# A075171 trees by binary runs in integers, coded to Dyck words |
84
|
|
|
|
|
|
|
# A071153 Lukasiewicz coded digits |
85
|
|
|
|
|
|
|
# |
86
|
|
|
|
|
|
|
my %oeis_anum = (HtoL => 'A014486', # balanced binary |
87
|
|
|
|
|
|
|
# OEIS-Catalogue: A014486 |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
LtoH => undef, |
90
|
|
|
|
|
|
|
); |
91
|
|
|
|
|
|
|
sub oeis_anum { |
92
|
1
|
|
|
1
|
1
|
3
|
my ($self) = @_; |
93
|
1
|
|
|
|
|
2
|
return $oeis_anum{$self->{'direction'}}; |
94
|
|
|
|
|
|
|
} |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
#------------------------------------------------------------------------------ |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
# When $self->{'wantlen'} becomes equal to _WANTLEN_TO_BIGINT then go to |
100
|
|
|
|
|
|
|
# Math::BigInt since the bits of a UV would be overflowed. |
101
|
|
|
|
|
|
|
# |
102
|
|
|
|
|
|
|
# _WANTLEN_TO_BIGINT is floor(numbits(UV)/2), but calculated by a probe of |
103
|
|
|
|
|
|
|
# "~0". |
104
|
|
|
|
|
|
|
# |
105
|
|
|
|
|
|
|
# On a 32-bit UV balance binary value=0xFFFF0000 is reached at i=48_760_366 |
106
|
|
|
|
|
|
|
# which is fairly big but might be reached by a long running loop. On a |
107
|
|
|
|
|
|
|
# 64-bit UV the corresponding limit is i=75*10^15 so would not be reached in |
108
|
|
|
|
|
|
|
# any reasonable time. |
109
|
|
|
|
|
|
|
# |
110
|
2
|
|
|
|
|
5
|
use constant 1.02 _WANTLEN_TO_BIGINT => do { |
111
|
2
|
|
|
|
|
2
|
my $uv = ~0; |
112
|
2
|
|
|
|
|
3
|
my $limit = 0; |
113
|
2
|
|
|
|
|
5
|
while ($uv >= 3) { |
114
|
64
|
|
|
|
|
33
|
$uv >>= 2; |
115
|
64
|
|
|
|
|
66
|
$limit++; |
116
|
|
|
|
|
|
|
} |
117
|
|
|
|
|
|
|
### $limit |
118
|
|
|
|
|
|
|
$limit |
119
|
2
|
|
|
2
|
|
7
|
}; |
|
2
|
|
|
|
|
25
|
|
|
2
|
|
|
|
|
2522
|
|
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
sub rewind { |
122
|
6
|
|
|
6
|
1
|
372
|
my ($self) = @_; |
123
|
6
|
|
|
|
|
16
|
$self->{'wantlen'} = 0; |
124
|
6
|
|
|
|
|
11
|
$self->{'bits'} = []; |
125
|
6
|
|
|
|
|
7
|
$self->{'value'} = 0; |
126
|
6
|
|
|
|
|
22
|
$self->{'i'} = $self->i_start; |
127
|
|
|
|
|
|
|
} |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
sub next { |
130
|
123
|
|
|
123
|
1
|
953
|
my ($self) = @_; |
131
|
|
|
|
|
|
|
### BalancedBinary next() ... |
132
|
123
|
|
|
|
|
110
|
my $bits = $self->{'bits'}; |
133
|
123
|
|
|
|
|
80
|
my $value; |
134
|
|
|
|
|
|
|
|
135
|
123
|
100
|
|
|
|
149
|
if (! @$bits) { |
136
|
|
|
|
|
|
|
### initial 2 ... |
137
|
4
|
|
|
|
|
8
|
push @$bits, 2; |
138
|
4
|
|
|
|
|
3
|
$value = 2; |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
} else { |
141
|
119
|
|
|
|
|
87
|
$value = $self->{'value'}; |
142
|
119
|
|
|
|
|
67
|
for (;;) { |
143
|
|
|
|
|
|
|
### at: "bits=".join(',',@{$self->{'bits'}}) |
144
|
181
|
100
|
|
|
|
212
|
if (scalar(@$bits) < 2) { |
145
|
|
|
|
|
|
|
### extend to wantlen: $self->{'wantlen'}+1 |
146
|
14
|
|
|
|
|
18
|
$value = ($bits->[0] *= 4); |
147
|
14
|
50
|
|
|
|
25
|
if (++$self->{'wantlen'} == _WANTLEN_TO_BIGINT) { |
148
|
|
|
|
|
|
|
### promote to BigInt from now on ... |
149
|
0
|
|
|
|
|
0
|
$bits->[0] = $value = _to_bigint($value); |
150
|
|
|
|
|
|
|
} |
151
|
14
|
|
|
|
|
11
|
last; |
152
|
|
|
|
|
|
|
} |
153
|
|
|
|
|
|
|
|
154
|
167
|
|
|
|
|
128
|
$value -= $bits->[-1]; |
155
|
167
|
|
|
|
|
126
|
my $bit = ($bits->[-1] *= 2); |
156
|
167
|
100
|
|
|
|
205
|
if ($bit < $bits->[-2]) { |
157
|
|
|
|
|
|
|
### shifted bit ... |
158
|
105
|
|
|
|
|
71
|
$value += $bit; |
159
|
105
|
|
|
|
|
85
|
last; |
160
|
|
|
|
|
|
|
} |
161
|
|
|
|
|
|
|
### drop this bit ... |
162
|
62
|
|
|
|
|
51
|
pop @$bits; |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
### pad for: "value=$value bits=".join(',',@$bits) |
166
|
|
|
|
|
|
|
# trailing bits ...,128, 32, 8, 2 |
167
|
119
|
|
|
|
|
105
|
my $bit = 2 + ($bits->[0]&1); # inherit BigInt |
168
|
119
|
|
|
|
|
159
|
foreach my $pos (reverse scalar(@$bits) .. $self->{'wantlen'}) { |
169
|
|
|
|
|
|
|
### pad with: $bit |
170
|
76
|
|
|
|
|
57
|
$bits->[$pos] = $bit; |
171
|
76
|
|
|
|
|
39
|
$value += $bit; |
172
|
76
|
|
|
|
|
64
|
$bit *= 4; |
173
|
|
|
|
|
|
|
} |
174
|
|
|
|
|
|
|
} |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
### return: "value=$value bits=".join(',',@$bits) |
177
|
|
|
|
|
|
|
return ($self->{'i'}++, |
178
|
123
|
|
|
|
|
204
|
$self->{'value'} = $value); |
179
|
|
|
|
|
|
|
} |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
sub ith { |
182
|
36
|
|
|
36
|
1
|
65
|
my ($self, $i) = @_; |
183
|
|
|
|
|
|
|
### BalancedBinary ith(): $i |
184
|
|
|
|
|
|
|
|
185
|
36
|
100
|
|
|
|
50
|
if ($i < 1) { |
186
|
4
|
|
|
|
|
4
|
return undef; |
187
|
|
|
|
|
|
|
} |
188
|
32
|
50
|
|
|
|
51
|
if (_is_infinite($i)) { |
189
|
0
|
|
|
|
|
0
|
return $i; |
190
|
|
|
|
|
|
|
} |
191
|
|
|
|
|
|
|
|
192
|
32
|
|
|
|
|
29
|
$i -= 1; |
193
|
|
|
|
|
|
|
### initial i remainder: $i |
194
|
|
|
|
|
|
|
|
195
|
32
|
|
|
|
|
26
|
my $zero = ($i*0); |
196
|
|
|
|
|
|
|
|
197
|
32
|
|
|
|
|
20
|
my @num; |
198
|
32
|
|
|
|
|
37
|
$num[0][0] = 0; |
199
|
32
|
|
|
|
|
29
|
$num[1][0] = 1; |
200
|
32
|
|
|
|
|
21
|
$num[1][1] = 1; |
201
|
32
|
|
|
|
|
18
|
my $z = 1; |
202
|
|
|
|
|
|
|
|
203
|
32
|
|
|
|
|
24
|
for ( ; ; $z++) { |
204
|
97
|
|
|
|
|
80
|
my $prev = $num[$z][0] = 1; # all zeros, no ones |
205
|
97
|
50
|
|
|
|
111
|
if ($z == 16) { |
206
|
0
|
|
|
|
|
0
|
$prev += $zero; |
207
|
0
|
0
|
|
|
|
0
|
if (! ref $zero) { |
208
|
|
|
|
|
|
|
### promote to BigInt ... |
209
|
0
|
|
|
|
|
0
|
$zero = _to_bigint($zero); |
210
|
|
|
|
|
|
|
} |
211
|
|
|
|
|
|
|
} |
212
|
97
|
|
|
|
|
99
|
foreach my $o (1 .. $z) { |
213
|
211
|
|
100
|
|
|
406
|
$num[$z][$o] |
214
|
|
|
|
|
|
|
= ($prev # 1... $num[$z][$o-1] |
215
|
|
|
|
|
|
|
+= ($num[$z-1][$o] || 0)); # 0... if $z>=1 |
216
|
|
|
|
|
|
|
} |
217
|
97
|
|
|
|
|
67
|
my $catalan = $num[$z][$z]; |
218
|
97
|
100
|
|
|
|
127
|
if ($i < $catalan) { |
219
|
32
|
|
|
|
|
29
|
last; |
220
|
|
|
|
|
|
|
} |
221
|
|
|
|
|
|
|
### subtract catalan: $catalan |
222
|
65
|
|
|
|
|
64
|
$i -= $catalan; |
223
|
|
|
|
|
|
|
} |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
### i remaining: $i |
226
|
32
|
|
|
|
|
32
|
my @ret = (1); |
227
|
32
|
|
|
|
|
29
|
my $o = $z-1; |
228
|
32
|
|
|
|
|
38
|
while ($o >= 1) { |
229
|
|
|
|
|
|
|
### at: "i=$i z=$z o=$o ret=".join('',@ret) |
230
|
|
|
|
|
|
|
### assert: $z >= $o |
231
|
|
|
|
|
|
|
|
232
|
110
|
100
|
|
|
|
121
|
if ($z > $o) { |
233
|
|
|
|
|
|
|
### compare: "z=".($z-1).",o=$o num=".($num[$z-1][$o]||'undef') |
234
|
75
|
|
|
|
|
65
|
my $znum = $num[$z-1][$o]; |
235
|
75
|
100
|
|
|
|
83
|
if ($i < $znum) { |
236
|
|
|
|
|
|
|
### 0 ... |
237
|
45
|
|
|
|
|
52
|
push @ret, 0; |
238
|
45
|
|
|
|
|
30
|
$z--; |
239
|
45
|
|
|
|
|
53
|
next; |
240
|
|
|
|
|
|
|
} |
241
|
30
|
|
|
|
|
17
|
$i -= $znum; |
242
|
|
|
|
|
|
|
} |
243
|
|
|
|
|
|
|
### 1 ... |
244
|
65
|
|
|
|
|
49
|
push @ret, 1; |
245
|
65
|
|
|
|
|
78
|
$o--; |
246
|
|
|
|
|
|
|
} |
247
|
|
|
|
|
|
|
|
248
|
32
|
|
|
|
|
34
|
push @ret, (0) x $z; |
249
|
|
|
|
|
|
|
### final: "ret=".join('',@ret) |
250
|
|
|
|
|
|
|
|
251
|
32
|
50
|
33
|
|
|
83
|
if (! ref $zero && @ret >= 2*_WANTLEN_TO_BIGINT) { |
252
|
|
|
|
|
|
|
### promote to BigInt ... |
253
|
0
|
|
|
|
|
0
|
$zero = _to_bigint($zero); |
254
|
|
|
|
|
|
|
} |
255
|
|
|
|
|
|
|
|
256
|
32
|
|
|
|
|
27
|
@ret = reverse @ret; |
257
|
|
|
|
|
|
|
### return: _digit_join(\@ret, 2, $zero) |
258
|
32
|
|
|
|
|
43
|
return _digit_join(\@ret, 2, $zero); |
259
|
|
|
|
|
|
|
} |
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
# $aref->[0] low digit |
262
|
|
|
|
|
|
|
sub _digit_join { |
263
|
32
|
|
|
32
|
|
29
|
my ($aref, $radix, $zero) = @_; |
264
|
32
|
|
|
|
|
21
|
my $n = $zero; |
265
|
32
|
|
|
|
|
33
|
foreach my $digit (reverse @$aref) { # high to low |
266
|
194
|
|
|
|
|
106
|
$n *= $radix; |
267
|
194
|
|
|
|
|
133
|
$n += $digit; |
268
|
|
|
|
|
|
|
} |
269
|
32
|
|
|
|
|
87
|
return $n; |
270
|
|
|
|
|
|
|
} |
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
sub value_to_i { |
273
|
58
|
|
|
58
|
1
|
168
|
my ($self, $value) = @_; |
274
|
|
|
|
|
|
|
### BalancedBinary value_to_i(): $value |
275
|
|
|
|
|
|
|
|
276
|
58
|
100
|
100
|
|
|
187
|
if ($value < 2 || $value != int($value)) { |
277
|
26
|
|
|
|
|
36
|
return undef; |
278
|
|
|
|
|
|
|
} |
279
|
32
|
50
|
|
|
|
987
|
if (_is_infinite($value)) { |
280
|
0
|
|
|
|
|
0
|
return $value; |
281
|
|
|
|
|
|
|
} |
282
|
|
|
|
|
|
|
|
283
|
32
|
50
|
|
|
|
2231
|
my @bits = _digit_split_lowtohigh($value,2) |
284
|
|
|
|
|
|
|
or return undef; |
285
|
|
|
|
|
|
|
|
286
|
32
|
100
|
|
|
|
62
|
_pred_on_bits($self,\@bits) |
287
|
|
|
|
|
|
|
or return undef; |
288
|
|
|
|
|
|
|
|
289
|
22
|
|
|
|
|
24
|
my @num; |
290
|
22
|
|
|
|
|
23
|
$num[0][0] = 0; |
291
|
22
|
|
|
|
|
22
|
$num[1][0] = 1; |
292
|
22
|
|
|
|
|
18
|
$num[1][1] = 1; |
293
|
22
|
|
|
|
|
28
|
my $w = scalar(@bits) / 2; |
294
|
|
|
|
|
|
|
### $w |
295
|
|
|
|
|
|
|
|
296
|
22
|
|
|
|
|
33
|
my $zero = $value*0; |
297
|
22
|
|
|
|
|
1173
|
my $i = 1 + $zero; |
298
|
|
|
|
|
|
|
|
299
|
22
|
|
|
|
|
905
|
foreach my $z (1 .. $w) { |
300
|
64
|
|
|
|
|
1718
|
my $prev = $num[$z][0] = 1; # all zeros, no ones |
301
|
64
|
50
|
|
|
|
94
|
if ($z > 16) { |
302
|
0
|
|
|
|
|
0
|
$prev += $zero; |
303
|
|
|
|
|
|
|
} |
304
|
64
|
|
|
|
|
71
|
foreach my $o (1 .. $z) { |
305
|
134
|
|
100
|
|
|
316
|
$num[$z][$o] |
306
|
|
|
|
|
|
|
= ($prev # 1... $num[$z][$o-1] |
307
|
|
|
|
|
|
|
+= ($num[$z-1][$o] || 0)); # 0... if $z>=1 |
308
|
|
|
|
|
|
|
} |
309
|
64
|
|
|
|
|
105
|
$i += $num[$z-1][$z-1]; |
310
|
|
|
|
|
|
|
} |
311
|
|
|
|
|
|
|
### base i: $i |
312
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
### bits: join('',@bits) |
314
|
22
|
|
|
|
|
805
|
shift @bits; # skip high 1-bit |
315
|
22
|
|
|
|
|
20
|
my $z = $w; |
316
|
22
|
|
|
|
|
22
|
my $o = $w-1; |
317
|
22
|
|
|
|
|
24
|
foreach my $bit (@bits) { # high to low |
318
|
|
|
|
|
|
|
### at: "z=$z o=$o bit=$bit" |
319
|
|
|
|
|
|
|
### assert: $o >= 0 |
320
|
|
|
|
|
|
|
### assert: $z >= $o |
321
|
106
|
100
|
|
|
|
117
|
if ($bit) { |
322
|
|
|
|
|
|
|
### bit 1 add: $num[$z-1][$o] |
323
|
42
|
|
100
|
|
|
124
|
$i += $num[$z-1][$o] || 0; |
324
|
42
|
|
|
|
|
1690
|
$o--; |
325
|
|
|
|
|
|
|
} else { |
326
|
64
|
|
|
|
|
57
|
$z--; |
327
|
|
|
|
|
|
|
} |
328
|
|
|
|
|
|
|
} |
329
|
22
|
|
|
|
|
59
|
return $i; |
330
|
|
|
|
|
|
|
} |
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
sub value_to_i_floor { |
333
|
954
|
|
|
954
|
1
|
4374
|
my ($self, $value) = @_; |
334
|
954
|
|
|
|
|
897
|
return _value_to_i_round ($self, $value, 0); |
335
|
|
|
|
|
|
|
} |
336
|
|
|
|
|
|
|
sub value_to_i_ceil { |
337
|
952
|
|
|
952
|
1
|
4333
|
my ($self, $value) = @_; |
338
|
952
|
|
|
|
|
833
|
return _value_to_i_round ($self, $value, 1); |
339
|
|
|
|
|
|
|
} |
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
# Return the i corresponding to $value. |
342
|
|
|
|
|
|
|
# If $value is not balanced binary then round according to $ceil. |
343
|
|
|
|
|
|
|
# $ceil=1 to round up, or $ceil=0 to round down. |
344
|
|
|
|
|
|
|
# |
345
|
|
|
|
|
|
|
sub _value_to_i_round { |
346
|
1906
|
|
|
1906
|
|
1290
|
my ($self, $value, $ceil) = @_; |
347
|
|
|
|
|
|
|
### _value_to_i_round(): $value |
348
|
|
|
|
|
|
|
|
349
|
1906
|
100
|
|
|
|
2171
|
if ($value < 2) { |
350
|
21
|
|
|
|
|
36
|
return $self->i_start(); |
351
|
|
|
|
|
|
|
} |
352
|
1885
|
50
|
|
|
|
3512
|
if (_is_infinite($value)) { |
353
|
0
|
|
|
|
|
0
|
return $value; |
354
|
|
|
|
|
|
|
} |
355
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
{ |
357
|
1885
|
|
|
|
|
5788
|
my $int = int($value); |
|
1885
|
|
|
|
|
1241
|
|
358
|
1885
|
100
|
|
|
|
2401
|
if ($value != $int) { |
359
|
32
|
|
|
|
|
34
|
$value = $int + $ceil; # +1 if not integer and want ceil |
360
|
|
|
|
|
|
|
} |
361
|
|
|
|
|
|
|
} |
362
|
1885
|
|
|
|
|
2799
|
my @bits = reverse _digit_split_lowtohigh($value,2); |
363
|
|
|
|
|
|
|
|
364
|
1885
|
100
|
|
|
|
2580
|
if (scalar(@bits) & 1) { |
365
|
|
|
|
|
|
|
# ENHANCE-ME: this is Catalan cumulative, or cumulative+1 |
366
|
|
|
|
|
|
|
### odd num bits ... |
367
|
681
|
|
|
|
|
1045
|
@bits = ((0) x scalar(@bits), 1); |
368
|
|
|
|
|
|
|
} |
369
|
|
|
|
|
|
|
### assert: (scalar(@bits) % 2) == 0 |
370
|
|
|
|
|
|
|
|
371
|
1885
|
|
|
|
|
1319
|
my @num; |
372
|
1885
|
|
|
|
|
1834
|
$num[0][0] = 0; |
373
|
1885
|
|
|
|
|
1319
|
$num[1][0] = 1; |
374
|
1885
|
|
|
|
|
1195
|
$num[1][1] = 1; |
375
|
1885
|
|
|
|
|
1518
|
my $w = scalar(@bits)/2; |
376
|
|
|
|
|
|
|
### $w |
377
|
|
|
|
|
|
|
|
378
|
1885
|
|
|
|
|
1320
|
my $zero = $value*0; |
379
|
1885
|
|
|
|
|
3636
|
my $i = 1 + $zero; |
380
|
|
|
|
|
|
|
|
381
|
1885
|
|
|
|
|
3874
|
foreach my $z (1 .. $w) { |
382
|
8492
|
|
|
|
|
10507
|
my $prev = $num[$z][0] = 1; # all zeros, no ones |
383
|
8492
|
50
|
|
|
|
9123
|
if ($z > 16) { |
384
|
0
|
|
|
|
|
0
|
$prev += $zero; |
385
|
|
|
|
|
|
|
} |
386
|
8492
|
|
|
|
|
6942
|
foreach my $o (1 .. $z) { |
387
|
24000
|
|
100
|
|
|
39339
|
$num[$z][$o] |
388
|
|
|
|
|
|
|
= ($prev # 1... $num[$z][$o-1] |
389
|
|
|
|
|
|
|
+= ($num[$z-1][$o] || 0)); # 0... if $z>=1 |
390
|
|
|
|
|
|
|
} |
391
|
8492
|
|
|
|
|
7752
|
$i += $num[$z-1][$z-1]; |
392
|
|
|
|
|
|
|
} |
393
|
|
|
|
|
|
|
### base i: $i |
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
### bits: join('',@bits) |
396
|
1885
|
|
|
|
|
2871
|
shift @bits; # skip high 1-bit |
397
|
1885
|
|
|
|
|
1267
|
my $z = $w; |
398
|
1885
|
|
|
|
|
1170
|
my $o = $w-1; |
399
|
|
|
|
|
|
|
|
400
|
1885
|
|
|
|
|
1579
|
foreach my $bit (@bits) { # high to low |
401
|
|
|
|
|
|
|
### at: "z=$z o=$o bit=$bit" |
402
|
|
|
|
|
|
|
### assert: $o >= 0 |
403
|
|
|
|
|
|
|
### assert: $z >= $o |
404
|
7186
|
100
|
|
|
|
6114
|
if ($bit) { |
405
|
2581
|
100
|
|
|
|
2705
|
if ($o == 0) { |
406
|
|
|
|
|
|
|
### all 1s used, rest round down to zeros, so done: $i + $ceil |
407
|
387
|
|
|
|
|
869
|
return $i + $ceil; |
408
|
|
|
|
|
|
|
} |
409
|
|
|
|
|
|
|
### bit 1 add: $num[$z-1][$o] |
410
|
2194
|
|
100
|
|
|
3420
|
$i += $num[$z-1][$o] || 0; |
411
|
2194
|
|
|
|
|
4954
|
$o--; |
412
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
} else { |
414
|
4605
|
100
|
|
|
|
5033
|
if ($z == $o) { |
415
|
|
|
|
|
|
|
### 0 out of place, round up to 101010 ... |
416
|
1323
|
|
|
|
|
1466
|
while ($o) { |
417
|
4413
|
|
50
|
|
|
8333
|
$i += $num[$o-1][$o] || 0; |
418
|
4413
|
|
|
|
|
4721
|
$o--; |
419
|
|
|
|
|
|
|
} |
420
|
1323
|
|
|
|
|
3004
|
return $i - (1-$ceil); |
421
|
|
|
|
|
|
|
} |
422
|
|
|
|
|
|
|
|
423
|
3282
|
|
|
|
|
2524
|
$z--; |
424
|
|
|
|
|
|
|
} |
425
|
|
|
|
|
|
|
} |
426
|
175
|
|
|
|
|
437
|
return $i; |
427
|
|
|
|
|
|
|
} |
428
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
# 1 10, |
432
|
|
|
|
|
|
|
# 2 1010, |
433
|
|
|
|
|
|
|
# 3 1100, |
434
|
|
|
|
|
|
|
# 4 101010, |
435
|
|
|
|
|
|
|
# 5 101100, |
436
|
|
|
|
|
|
|
# 6 110010, |
437
|
|
|
|
|
|
|
# 7 110100, |
438
|
|
|
|
|
|
|
# 8 111000, |
439
|
|
|
|
|
|
|
# 9 10101010, 170 |
440
|
|
|
|
|
|
|
# |
441
|
|
|
|
|
|
|
# 10xxxx |
442
|
|
|
|
|
|
|
# 1xxxx0 |
443
|
|
|
|
|
|
|
# num(width) = 2*num(width-1) + extra |
444
|
|
|
|
|
|
|
# num(1) = 1 |
445
|
|
|
|
|
|
|
# num(2) = 2*1 = 2 |
446
|
|
|
|
|
|
|
# num(3) = 2*2 + 1 = 5 |
447
|
|
|
|
|
|
|
# total(width) |
448
|
|
|
|
|
|
|
# = num(1) + num(2) + num(3) + ... + num(width) |
449
|
|
|
|
|
|
|
# = 1 + 2*1 + 2*2+1 + |
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
sub pred { |
452
|
364
|
|
|
364
|
1
|
848
|
my ($self, $value) = @_; |
453
|
|
|
|
|
|
|
### BalancedBinary pred(): $value |
454
|
|
|
|
|
|
|
|
455
|
364
|
100
|
66
|
|
|
620
|
if ($value != int($value) || _is_infinite($value)) { |
456
|
176
|
|
|
|
|
146
|
return 0; |
457
|
|
|
|
|
|
|
} |
458
|
|
|
|
|
|
|
|
459
|
188
|
50
|
|
|
|
274
|
my @bits = _digit_split_lowtohigh($value,2) |
460
|
|
|
|
|
|
|
or return 0; |
461
|
188
|
|
|
|
|
218
|
return _pred_on_bits($self,\@bits); |
462
|
|
|
|
|
|
|
} |
463
|
|
|
|
|
|
|
sub _pred_on_bits { |
464
|
220
|
|
|
220
|
|
155
|
my ($self, $bits) = @_; |
465
|
|
|
|
|
|
|
### _pred_on_bits(): $bits |
466
|
|
|
|
|
|
|
|
467
|
220
|
100
|
|
|
|
266
|
if (scalar(@$bits) & 1) { |
468
|
84
|
|
|
|
|
94
|
return 0; |
469
|
|
|
|
|
|
|
} |
470
|
|
|
|
|
|
|
|
471
|
136
|
50
|
|
|
|
220
|
if ($self->{'direction'} eq 'HtoL') { |
472
|
136
|
|
|
|
|
219
|
@$bits = reverse @$bits; |
473
|
|
|
|
|
|
|
### reversed bits: @$bits |
474
|
|
|
|
|
|
|
} |
475
|
|
|
|
|
|
|
|
476
|
136
|
|
|
|
|
134
|
my @count = (0,0); |
477
|
136
|
|
|
|
|
118
|
foreach my $bit (@$bits) { |
478
|
666
|
|
|
|
|
387
|
$count[$bit]++; |
479
|
666
|
100
|
|
|
|
754
|
if ($count[0] > $count[1]) { |
480
|
58
|
|
|
|
|
83
|
return 0; |
481
|
|
|
|
|
|
|
} |
482
|
|
|
|
|
|
|
} |
483
|
|
|
|
|
|
|
### @count |
484
|
78
|
|
|
|
|
133
|
return ($count[0] == $count[1]); |
485
|
|
|
|
|
|
|
} |
486
|
|
|
|
|
|
|
|
487
|
|
|
|
|
|
|
# w = log2(value) / 2 |
488
|
|
|
|
|
|
|
# Catalan = 4^w / (sqrt(Pi * w) * (w + 1)) |
489
|
|
|
|
|
|
|
# = 4^(log2(v)/2) / (sqrt(pi*log2(v)/2) * (log2(v)/2+1)) |
490
|
|
|
|
|
|
|
# = v / (sqrt(pi*log2(v)/2) * (log2(v)/2+1)) |
491
|
|
|
|
|
|
|
# = v / (sqrt(pi*log2(v)/2) * (log2(v)+2)/2) |
492
|
|
|
|
|
|
|
# = v / (sqrt(pi*log2(v)/2)/2 * (log2(v)+2)) |
493
|
|
|
|
|
|
|
# = v / (sqrt(pi/8*log2(v)) * (log2(v)+2)) |
494
|
|
|
|
|
|
|
# |
495
|
|
|
|
|
|
|
# if value has 2*w bits then cumulative catalan |
496
|
|
|
|
|
|
|
# i = sum w=0 to log2(value)/2 |
497
|
|
|
|
|
|
|
# of value / (sqrt(pi/8*log2(value)) * (log2(value)+2)) |
498
|
|
|
|
|
|
|
# |
499
|
|
|
|
|
|
|
# is cumulative close enough to the plain ? |
500
|
|
|
|
|
|
|
# |
501
|
|
|
|
|
|
|
# 2*w bits, ipart=Catalan(w) value=4^w |
502
|
|
|
|
|
|
|
# so w = log4(value) |
503
|
|
|
|
|
|
|
# ipart = Catalan(log4(value)) |
504
|
|
|
|
|
|
|
# = |
505
|
|
|
|
|
|
|
|
506
|
|
|
|
|
|
|
sub value_to_i_estimate { |
507
|
20
|
|
|
20
|
1
|
1205
|
my ($self, $value) = @_; |
508
|
|
|
|
|
|
|
### value_to_i_estimate: $value |
509
|
|
|
|
|
|
|
|
510
|
20
|
100
|
|
|
|
27
|
if ($value <= 2) { |
511
|
8
|
|
|
|
|
8
|
return 1; |
512
|
|
|
|
|
|
|
} |
513
|
|
|
|
|
|
|
|
514
|
12
|
|
|
|
|
82
|
my $log2 = _blog2_estimate($value); |
515
|
12
|
100
|
|
|
|
240
|
if (! defined $log2) { |
516
|
11
|
|
|
|
|
16
|
$log2 = log($value) * (1/log(2)); |
517
|
|
|
|
|
|
|
} |
518
|
12
|
|
|
|
|
16
|
$log2 = max($log2,1); |
519
|
|
|
|
|
|
|
|
520
|
12
|
100
|
66
|
|
|
23
|
if (ref $value && $value->isa('Math::BigInt')) { |
521
|
|
|
|
|
|
|
# oldish BigInt doesn't like to divide BigInt/NV |
522
|
1
|
|
|
|
|
924
|
require Math::BigFloat; |
523
|
1
|
|
|
|
|
13417
|
$value = Math::BigFloat->new($value); |
524
|
|
|
|
|
|
|
} |
525
|
|
|
|
|
|
|
|
526
|
12
|
|
|
|
|
663
|
return max(1, |
527
|
|
|
|
|
|
|
int($value / (sqrt((3.141592/8)*$log2) * ($log2+1)))); |
528
|
|
|
|
|
|
|
} |
529
|
|
|
|
|
|
|
|
530
|
|
|
|
|
|
|
1; |
531
|
|
|
|
|
|
|
__END__ |