1 // Written in the D programming language.
2 /*
3 NYSL Version 0.9982
4 
5 A. This software is "Everyone'sWare". It means:
6   Anybody who has this software can use it as if he/she is
7   the author.
8 
9   A-1. Freeware. No fee is required.
10   A-2. You can freely redistribute this software.
11   A-3. You can freely modify this software. And the source
12       may be used in any software with no limitation.
13   A-4. When you release a modified version to public, you
14       must publish it with your name.
15 
16 B. The author is not responsible for any kind of damages or loss
17   while using or misusing this software, which is distributed
18   "AS IS". No warranty of any kind is expressed or implied.
19   You use AT YOUR OWN RISK.
20 
21 C. Copyrighted to Kazuki KOMATSU
22 
23 D. Above three clauses are applied both to source and binary
24   form of this software.
25 */
26 
27 /**
28 このモジュールは、標準ライブラリstd.mathの拡張です。
29 */
30 module carbon.math;
31 
32 import std.math;
33 import std.traits;
34 import std.array;
35 import std.range;
36 import std.typecons;
37 
38 
39 real toDeg(real rad) pure nothrow @safe
40 {
41     return rad / PI * 180;
42 }
43 
44 
45 real toRad(real deg) pure nothrow @safe
46 {
47     return deg / 180 * PI;
48 }
49 
50 
51 bool isPowOf2(I)(I n)
52 if(is(typeof(n && (n & (n-1)) == 0 )))
53 {
54     return n && (n & (n-1)) == 0;
55 }
56 
57 unittest{
58     assert(!0.isPowOf2);
59     assert( 1.isPowOf2);
60     assert( 2.isPowOf2);
61     assert( 4.isPowOf2);
62     assert(!6.isPowOf2);
63     assert( 8.isPowOf2);
64     assert(!9.isPowOf2);
65     assert(!10.isPowOf2);
66 }
67 
68 
69 T sqrtFloor(T, F)(F x)
70 if(isFloatingPoint!F)
71 {
72     return cast(T)(sqrt(x));
73 }
74 
75 
76 T sqrtCeil(T, F)(F x)
77 if(isFloatingPoint!F)
78 {
79     return cast(T)(sqrt(x).ceil());
80 }
81 
82 
83 T lcm(T)(T x, T y)
84 {
85     return x * (y / gcd(x, y));
86 }
87 
88 
89 pure bool isPrime(T)(T src)if(__traits(isIntegral,T)){
90     if(src <= 1)return false;
91     else if(src < 4)return true;
92     else if(!(src&1))return false;
93     else if(((src+1)%6) && ((src-1)%6))return false;
94     
95     T root = cast(T)sqrt(cast(real)src) + 1;
96     
97     for(T i = 5; i < root; i += 6)
98         if(!((src%i) && ((src)%(i+2))))
99             return false;
100 
101     return true;
102 }
103 
104 
105 void primeFactors(T, R)(T n, ref R or)
106 if(isOutputRange!(R, Tuple!(T, uint)))
107 {
108     alias E = Tuple!(T, uint);
109 
110     if(n < 0){
111         primeFactors(-n, or);
112         return;
113     }
114 
115     if(n <= 1){
116         return;
117     }
118 
119     import core.bitop;
120 
121   static if(is(T == long) || is(T == ulong))
122   {
123     {
124         uint cnt;
125         immutable uint lns = n & uint.max;
126         if(auto c = bsf(lns))
127             cnt = c;
128         else if(lns == 0)
129             cnt = bsf(cast(uint)(n >> 32)) + 32;
130 
131         if(cnt){
132             put(or, E(2, cnt));
133             n >>= cnt;
134         }
135     }
136   }
137   else
138   {
139     if(auto cnt = bsf(n)){
140         put(or, E(2, cnt));
141         n >>= cnt;
142     }
143   }
144 
145     if(isPrime(n)){
146         put(or, E(n, 1));
147         return;
148     }
149 
150     // Fermat's method
151     {
152         T x = cast(T)sqrt(cast(real)n),
153           y = 0;
154 
155         T diff = x^^2 - n;
156         {
157             T cnt = 3;
158             bool sw;
159             while(diff != 0){
160                 if(n % cnt == 0){
161                     // p = n / cnt, q = cnt
162                     auto p = n / cnt;
163                     x = (p + cnt) / 2;
164                     y = (p - cnt) / 2;
165                     diff = 0;
166                     break;
167                 }
168                 cnt += 2;
169 
170                 if(diff < 0){
171                     diff += 2*x + 1;
172                     ++x;
173                 }else if(!sw && diff > 2*y+1){
174                     auto m = cast(T)ceil(sqrt((cast(real)y)^^2 + diff) - y);
175                     diff -= m * (m + 2 * y);
176                     y += m;
177                 }else{
178                     sw = true;
179                     diff -= 2*y + 1;
180                     ++y;
181                 }
182             }
183         }
184 
185         T p = x + y,
186           q = x - y;
187 
188         if(p == q){
189             auto dlg = (E e){
190                 e[1] *= 2;
191                 put(or, e);
192             };
193 
194             primeFactors(p, dlg);
195             return;
196         }
197 
198         if(isPrime(q)){
199             uint c = 1;
200             while(p % q == 0){
201                 p /= q;
202                 ++c;
203             }
204 
205             put(or, E(q, c));
206         }else{
207             {
208                 auto dlg = (E e){
209                     while(p % e[0] == 0){
210                         p /= e[0];
211                         ++e[1];
212                     }
213 
214                     put(or, e);
215                 };
216 
217                 primeFactors(q, dlg);
218             }
219         }
220 
221         primeFactors(p, or);
222     }
223 }
224 
225 
226 Tuple!(T, uint)[] primeFactors(T)(T n)
227 {
228     auto app = appender!(typeof(return))();
229     primeFactors(n, app);
230     return app.data;
231 }
232 
233 
234 unittest
235 {
236     foreach(n; 2 .. 100000){
237         ulong m = 1;
238         foreach(ps; primeFactors(n))
239             m *= ps[0] ^^ ps[1];
240 
241         assert(m == n);
242     }
243 
244     foreach(n; 10_000_000L .. 10_001_000L){
245         ulong m = 1;
246         foreach(ps; primeFactors(n))
247             m *= ps[0] ^^ ps[1];
248 
249         assert(m == n);
250     }
251 }
252 
253 
254 void primeFactorsSimple(T, R)(T n, ref R or)
255 if(isOutputRange!(R, Tuple!(T, uint)))
256 {
257     alias E = Tuple!(T, uint);
258     T m = 2;
259     while(n != 1){
260         if(isPrime(n)){
261             put(or, E(n, 1));
262             return;
263         }
264 
265         uint c;
266         while(n % m == 0){
267             n /= m;
268             ++c;
269         }
270 
271         if(c) put(or, E(m, c));
272         ++m;
273     }
274 }
275 
276 
277 Tuple!(T, uint)[] primeFactorsSimple(T)(T n)
278 {
279     auto app = appender!(typeof(return))();
280     primeFactorsSimple(n, app);
281     return app.data;
282 }
283 
284 
285 unittest
286 {
287     foreach(n; 2 .. 100000){
288         ulong m = 1;
289         foreach(ps; primeFactorsSimple(n))
290             m *= ps[0] ^^ ps[1];
291 
292         assert(m == n);
293     }
294 
295     foreach(n; 10_000_000L .. 10_001_000L){
296         ulong m = 1;
297         foreach(ps; primeFactorsSimple(n))
298             m *= ps[0] ^^ ps[1];
299 
300         assert(m == n);
301     }
302 }