1 /**
2 This module implements functions for the "Math" namespace in the scripting language.
3 See https://pillager86.github.io/dmildew/Math.html
4 
5 ────────────────────────────────────────────────────────────────────────────────
6 
7 Copyright (C) 2021 pillager86.rf.gd
8 
9 This program is free software: you can redistribute it and/or modify it under 
10 the terms of the GNU General Public License as published by the Free Software 
11 Foundation, either version 3 of the License, or (at your option) any later 
12 version.
13 
14 This program is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
16 PARTICULAR PURPOSE.  See the GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License along with 
19 this program.  If not, see <https://www.gnu.org/licenses/>.
20 */
21 module mildew.stdlib.math;
22 
23 import math=std.math;
24 
25 import mildew.environment;
26 import mildew.interpreter;
27 import mildew.types;
28 
29 /**
30  * Initializes the math library. This is called by Interpreter.initializeStdlib. Functions
31  * are stored in the global Math object and are accessed such as "Math.acos". Documentation
32  * for this library can be found at https://pillager86.github.io/dmildew/Math.html
33  * Params:
34  *  interpreter = The Interpreter object to load the namespace into.
35  */
36 public void initializeMathLibrary(Interpreter interpreter)
37 {
38     // TODO rewrite this mess with mixins
39     ScriptObject mathNamespace = new ScriptObject("Math", null, null);
40     // static members
41     mathNamespace["E"] = ScriptAny(cast(double)math.E);
42     mathNamespace["LN10"] = ScriptAny(cast(double)math.LN10);
43     mathNamespace["LN2"] = ScriptAny(cast(double)math.LN2);
44     mathNamespace["LOG10E"] = ScriptAny(cast(double)math.LOG10E);
45     mathNamespace["LOG2E"] = ScriptAny(cast(double)math.LOG2E);
46     mathNamespace["PI"] = ScriptAny(cast(double)math.PI);
47     mathNamespace["SQRT1_2"] = ScriptAny(cast(double)math.SQRT1_2);
48     mathNamespace["SQRT2"] = ScriptAny(cast(double)math.SQRT2);
49     // functions
50     mathNamespace["abs"] = ScriptAny(new ScriptFunction("Math.abs", &native_Math_abs));
51     mathNamespace["acos"] = ScriptAny(new ScriptFunction("Math.acos", &native_Math_acos));
52     mathNamespace["acosh"] = ScriptAny(new ScriptFunction("Math.acosh", &native_Math_acosh));
53     mathNamespace["asin"] = ScriptAny(new ScriptFunction("Math.asin", &native_Math_asin));
54     mathNamespace["asinh"] = ScriptAny(new ScriptFunction("Math.asinh", &native_Math_asinh));
55     mathNamespace["atan"] = ScriptAny(new ScriptFunction("Math.atan", &native_Math_atan));
56     mathNamespace["atan2"] = ScriptAny(new ScriptFunction("Math.atan2", &native_Math_atan2));
57     mathNamespace["cbrt"] = ScriptAny(new ScriptFunction("Math.cbrt", &native_Math_cbrt));
58     mathNamespace["ceil"] = ScriptAny(new ScriptFunction("Math.ceil", &native_Math_ceil));
59     mathNamespace["clz32"] = ScriptAny(new ScriptFunction("Math.clz32", &native_Math_clz32));
60     mathNamespace["cos"] = ScriptAny(new ScriptFunction("Math.cos", &native_Math_cos));
61     mathNamespace["cosh"] = ScriptAny(new ScriptFunction("Math.cosh", &native_Math_cosh));
62     mathNamespace["exp"] = ScriptAny(new ScriptFunction("Math.exp", &native_Math_exp));
63     mathNamespace["expm1"] = ScriptAny(new ScriptFunction("Math.expm1", &native_Math_expm1));
64     mathNamespace["floor"] = ScriptAny(new ScriptFunction("Math.floor", &native_Math_floor));
65     mathNamespace["fround"] = ScriptAny(new ScriptFunction("Math.fround", &native_Math_fround));
66     mathNamespace["hypot"] = ScriptAny(new ScriptFunction("Math.hypot", &native_Math_hypot));
67     mathNamespace["imul"] = ScriptAny(new ScriptFunction("Math.imul", &native_Math_imul));
68     mathNamespace["log"] = ScriptAny(new ScriptFunction("Math.log", &native_Math_log));
69     mathNamespace["log10"] = ScriptAny(new ScriptFunction("Math.log10", &native_Math_log10));
70     mathNamespace["log1p"] = ScriptAny(new ScriptFunction("Math.log1p", &native_Math_log1p));
71     mathNamespace["log2"] = ScriptAny(new ScriptFunction("Math.log2", &native_Math_log2));
72     mathNamespace["max"] = ScriptAny(new ScriptFunction("Math.max", &native_Math_max));
73     mathNamespace["min"] = ScriptAny(new ScriptFunction("Math.min", &native_Math_min));
74     mathNamespace["pow"] = ScriptAny(new ScriptFunction("Math.pow", &native_Math_pow));
75     mathNamespace["random"] = ScriptAny(new ScriptFunction("Math.random", &native_Math_random));
76     mathNamespace["round"] = ScriptAny(new ScriptFunction("Math.round", &native_Math_round));
77     mathNamespace["sign"] = ScriptAny(new ScriptFunction("Math.sign", &native_Math_sign));
78     mathNamespace["sin"] = ScriptAny(new ScriptFunction("Math.sin", &native_Math_sin));
79     mathNamespace["sinh"] = ScriptAny(new ScriptFunction("Math.sinh", &native_Math_sinh));
80     mathNamespace["sqrt"] = ScriptAny(new ScriptFunction("Math.sqrt", &native_Math_sqrt));
81     mathNamespace["tan"] = ScriptAny(new ScriptFunction("Math.tan", &native_Math_tan));
82     mathNamespace["tanh"] = ScriptAny(new ScriptFunction("Math.tanh", &native_Math_tanh));
83     mathNamespace["trunc"] = ScriptAny(new ScriptFunction("Math.trunc", &native_Math_trunc));
84     interpreter.forceSetGlobal("Math", mathNamespace, true);
85 }
86 
87 // TODO rewrite half of this mess with mixins
88 
89 private ScriptAny native_Math_abs(Environment env,
90                                   ScriptAny* thisObj,
91                                   ScriptAny[] args,
92                                   ref NativeFunctionError nfe)
93 {
94     if(args.length < 1)
95         return ScriptAny(double.nan);
96     if(!args[0].isNumber)
97         return ScriptAny(double.nan);
98     if(args[0].type == ScriptAny.Type.INTEGER)
99         return ScriptAny(math.abs(args[0].toValue!long));
100     return ScriptAny(math.abs(args[0].toValue!double));            
101 }
102 
103 private ScriptAny native_Math_acos(Environment env,
104                                    ScriptAny* thisObj,
105                                    ScriptAny[] args,
106                                    ref NativeFunctionError nfe)
107 {
108     if(args.length < 1)
109         return ScriptAny(double.nan);
110     if(!args[0].isNumber)
111         return ScriptAny(double.nan);
112     return ScriptAny(math.acos(args[0].toValue!double));
113 }
114 
115 private ScriptAny native_Math_acosh(Environment env,
116                                     ScriptAny* thisObj,
117                                     ScriptAny[] args,
118                                     ref NativeFunctionError nfe)
119 {
120     if(args.length < 1)
121         return ScriptAny(double.nan);
122     if(!args[0].isNumber)
123         return ScriptAny(double.nan);
124     return ScriptAny(math.acosh(args[0].toValue!double));
125 }
126 
127 private ScriptAny native_Math_asin(Environment env,
128                                    ScriptAny* thisObj,
129                                    ScriptAny[] args,
130                                    ref NativeFunctionError nfe)
131 {
132     if(args.length < 1)
133         return ScriptAny(double.nan);
134     if(!args[0].isNumber)
135         return ScriptAny(double.nan);
136     return ScriptAny(math.asin(args[0].toValue!double));
137 }
138 
139 private ScriptAny native_Math_asinh(Environment env,
140                                     ScriptAny* thisObj,
141                                     ScriptAny[] args,
142                                     ref NativeFunctionError nfe)
143 {
144     if(args.length < 1)
145         return ScriptAny(double.nan);
146     if(!args[0].isNumber)
147         return ScriptAny(double.nan);
148     return ScriptAny(math.asinh(args[0].toValue!double));
149 }
150 
151 private ScriptAny native_Math_atan(Environment env,
152                                    ScriptAny* thisObj,
153                                    ScriptAny[] args,
154                                    ref NativeFunctionError nfe)
155 {
156     if(args.length < 1)
157         return ScriptAny(double.nan);
158     if(!args[0].isNumber)
159         return ScriptAny(double.nan);
160     return ScriptAny(math.atan(args[0].toValue!double));
161 }
162 
163 private ScriptAny native_Math_atan2(Environment env,
164                                     ScriptAny* thisObj,
165                                     ScriptAny[] args,
166                                     ref NativeFunctionError nfe)
167 {
168     if(args.length < 2)
169         return ScriptAny(double.nan);
170     if(!args[0].isNumber || !args[1].isNumber)
171         return ScriptAny(double.nan);
172     return ScriptAny(math.atan2(args[0].toValue!double, args[1].toValue!double));
173 }
174 
175 private ScriptAny native_Math_cbrt(Environment env,
176                                    ScriptAny* thisObj,
177                                    ScriptAny[] args,
178                                    ref NativeFunctionError nfe)
179 {
180     if(args.length < 1)
181         return ScriptAny(double.nan);
182     if(!args[0].isNumber)
183         return ScriptAny(double.nan);
184     return ScriptAny(math.cbrt(args[0].toValue!double));
185 }
186 
187 private ScriptAny native_Math_ceil(Environment env,
188                                    ScriptAny* thisObj,
189                                    ScriptAny[] args,
190                                    ref NativeFunctionError nfe)
191 {
192     if(args.length < 1)
193         return ScriptAny(double.nan);
194     if(!args[0].isNumber)
195         return ScriptAny(double.nan);
196     if(args[0].isInteger)
197         return ScriptAny(args[0].toValue!long);
198     return ScriptAny(cast(long)math.ceil(args[0].toValue!double));
199 }
200 
201 private ScriptAny native_Math_clz32(Environment env,
202                                     ScriptAny* thisObj,
203                                     ScriptAny[] args,
204                                     ref NativeFunctionError nfe)
205 {
206     if(args.length < 1)
207         return ScriptAny(0);
208     if(!args[0].isNumber)
209         return ScriptAny(0);
210     immutable uint num = args[0].toValue!uint;
211     return ScriptAny(CLZ1(num));
212 }
213 
214 private ScriptAny native_Math_cos(Environment env,
215                                   ScriptAny* thisObj,
216                                   ScriptAny[] args,
217                                   ref NativeFunctionError nfe)
218 {
219     if(args.length < 1)
220         return ScriptAny(double.nan);
221     if(!args[0].isNumber)
222         return ScriptAny(double.nan);
223     return ScriptAny(math.cos(args[0].toValue!double));
224 }
225 
226 private ScriptAny native_Math_cosh(Environment env,
227                                    ScriptAny* thisObj,
228                                    ScriptAny[] args,
229                                    ref NativeFunctionError nfe)
230 {
231     if(args.length < 1)
232         return ScriptAny(double.nan);
233     if(!args[0].isNumber)
234         return ScriptAny(double.nan);
235     return ScriptAny(math.cosh(args[0].toValue!double));
236 }
237 
238 private ScriptAny native_Math_exp(Environment env,
239                                   ScriptAny* thisObj,
240                                   ScriptAny[] args,
241                                   ref NativeFunctionError nfe)
242 {
243     if(args.length < 1)
244         return ScriptAny(double.nan);
245     if(!args[0].isNumber)
246         return ScriptAny(double.nan);
247     return ScriptAny(math.exp(args[0].toValue!double));
248 }
249 
250 private ScriptAny native_Math_expm1(Environment env,
251                                     ScriptAny* thisObj,
252                                     ScriptAny[] args,
253                                     ref NativeFunctionError nfe)
254 {
255     if(args.length < 1)
256         return ScriptAny(double.nan);
257     if(!args[0].isNumber)
258         return ScriptAny(double.nan);
259     return ScriptAny(math.expm1(args[0].toValue!double));
260 }
261 
262 private ScriptAny native_Math_floor(Environment env,
263                                     ScriptAny* thisObj,
264                                     ScriptAny[] args,
265                                     ref NativeFunctionError nfe)
266 {
267     if(args.length < 1)
268         return ScriptAny(double.nan);
269     if(!args[0].isNumber)
270         return ScriptAny(double.nan);
271     if(args[0].isInteger)
272         return ScriptAny(args[0].toValue!long);
273     return ScriptAny(cast(long)math.floor(args[0].toValue!double));
274 }
275 
276 private ScriptAny native_Math_fround(Environment env,
277                                      ScriptAny* thisObj,
278                                      ScriptAny[] args,
279                                      ref NativeFunctionError nfe)
280 {
281     if(args.length < 1)
282         return ScriptAny(double.nan);
283     if(!args[0].isNumber)
284         return ScriptAny(double.nan);
285     immutable float f = args[0].toValue!float;
286     return ScriptAny(f);
287 }
288 
289 private ScriptAny native_Math_hypot(Environment env,
290                                     ScriptAny* thisObj,
291                                     ScriptAny[] args,
292                                     ref NativeFunctionError nfe)
293 {
294     double sum = 0;
295     foreach(arg ; args)
296     {
297         if(!arg.isNumber)
298             return ScriptAny(double.nan);
299         sum += arg.toValue!double * arg.toValue!double;
300     }
301     return ScriptAny(math.sqrt(sum));
302 }
303 
304 private ScriptAny native_Math_imul(Environment env,
305                                    ScriptAny* thisObj,
306                                    ScriptAny[] args,
307                                    ref NativeFunctionError nfe)
308 {
309     if(args.length < 2)
310         return ScriptAny(double.nan);
311     if(!args[0].isNumber || !args[1].isNumber)
312         return ScriptAny(double.nan);
313     immutable a = args[0].toValue!int;
314     immutable b = args[1].toValue!int;
315     return ScriptAny(a * b);
316 }
317 
318 private ScriptAny native_Math_log(Environment env,
319                                   ScriptAny* thisObj,
320                                   ScriptAny[] args,
321                                   ref NativeFunctionError nfe)
322 {
323     if(args.length < 1)
324         return ScriptAny(double.nan);
325     if(!args[0].isNumber)
326         return ScriptAny(double.nan);
327     return ScriptAny(math.log(args[0].toValue!double));
328 }
329 
330 private ScriptAny native_Math_log10(Environment env,
331                                     ScriptAny* thisObj,
332                                     ScriptAny[] args,
333                                     ref NativeFunctionError nfe)
334 {
335     if(args.length < 1)
336         return ScriptAny(double.nan);
337     if(!args[0].isNumber)
338         return ScriptAny(double.nan);
339     return ScriptAny(math.log10(args[0].toValue!double));
340 }
341 
342 private ScriptAny native_Math_log1p(Environment env,
343                                     ScriptAny* thisObj,
344                                     ScriptAny[] args,
345                                     ref NativeFunctionError nfe)
346 {
347     if(args.length < 1)
348         return ScriptAny(double.nan);
349     if(!args[0].isNumber)
350         return ScriptAny(double.nan);
351     return ScriptAny(math.log1p(args[0].toValue!double));
352 }
353 
354 private ScriptAny native_Math_log2(Environment env,
355                                    ScriptAny* thisObj,
356                                    ScriptAny[] args,
357                                    ref NativeFunctionError nfe)
358 {
359     if(args.length < 1)
360         return ScriptAny(double.nan);
361     if(!args[0].isNumber)
362         return ScriptAny(double.nan);
363     return ScriptAny(math.log2(args[0].toValue!double));
364 }
365 
366 private ScriptAny native_Math_max(Environment env,
367                                   ScriptAny* thisObj,
368                                   ScriptAny[] args,
369                                   ref NativeFunctionError nfe)
370 {
371     import std.algorithm: max;
372     if(args.length < 1)
373         return ScriptAny(double.nan);
374     if(!args[0].isNumber)
375         return ScriptAny(double.nan);
376     double maxNumber = args[0].toValue!double;
377     for(size_t i = 1; i < args.length; ++i)
378     {
379         if(!args[i].isNumber)
380             return ScriptAny.UNDEFINED;
381         immutable temp = args[i].toValue!double;
382         if(temp > maxNumber)
383             maxNumber = temp;
384     }
385     return ScriptAny(maxNumber);
386 }
387 
388 private ScriptAny native_Math_min(Environment env,
389                                   ScriptAny* thisObj,
390                                   ScriptAny[] args,
391                                   ref NativeFunctionError nfe)
392 {
393     import std.algorithm: max;
394     if(args.length < 1)
395         return ScriptAny(double.nan);
396     if(!args[0].isNumber)
397         return ScriptAny(double.nan);
398     double minNumber = args[0].toValue!double;
399     for(size_t i = 1; i < args.length; ++i)
400     {
401         if(!args[i].isNumber)
402             return ScriptAny.UNDEFINED;
403         immutable temp = args[i].toValue!double;
404         if(temp < minNumber)
405             minNumber = temp;
406     }
407     return ScriptAny(minNumber);
408 }
409 
410 private ScriptAny native_Math_pow(Environment env,
411                                   ScriptAny* thisObj,
412                                   ScriptAny[] args,
413                                   ref NativeFunctionError nfe)
414 {
415     if(args.length < 2)
416         return ScriptAny(double.nan);
417     if(!args[0].isNumber || !args[1].isNumber)
418         return ScriptAny(double.nan);
419     return ScriptAny(math.pow(args[0].toValue!double, args[1].toValue!double));
420 }
421 
422 private ScriptAny native_Math_random(Environment env,
423                                      ScriptAny* thisObj,
424                                      ScriptAny[] args,
425                                      ref NativeFunctionError nfe)
426 {
427     import std.random : uniform;
428     return ScriptAny(uniform(0.0, 1.0));
429 }
430 
431 private ScriptAny native_Math_round(Environment env,
432                                     ScriptAny* thisObj,
433                                     ScriptAny[] args,
434                                     ref NativeFunctionError nfe)
435 {
436     if(args.length < 1)
437         return ScriptAny(double.nan);
438     if(!args[0].isNumber)
439         return ScriptAny(double.nan);
440     if(args[0].isInteger)
441         return ScriptAny(args[0].toValue!long);
442     return ScriptAny(cast(long)math.round(args[0].toValue!double));
443 }
444 
445 private ScriptAny native_Math_sign(Environment env,
446                                    ScriptAny* thisObj,
447                                    ScriptAny[] args,
448                                    ref NativeFunctionError nfe)
449 {
450     if(args.length < 1)
451         return ScriptAny(double.nan);
452     if(!args[0].isNumber)
453         return ScriptAny(double.nan);
454     immutable num = args[0].toValue!double;
455     if(num < 0)
456         return ScriptAny(-1);
457     else if(num > 0)
458         return ScriptAny(1);
459     else
460         return ScriptAny(0);
461 }
462 
463 private ScriptAny native_Math_sin(Environment env,
464                                   ScriptAny* thisObj,
465                                   ScriptAny[] args,
466                                   ref NativeFunctionError nfe)
467 {
468     if(args.length < 1)
469         return ScriptAny(double.nan);
470     if(!args[0].isNumber)
471         return ScriptAny(double.nan);
472     return ScriptAny(math.sin(args[0].toValue!double));
473 }
474 
475 private ScriptAny native_Math_sinh(Environment env,
476         ScriptAny* thisObj,
477         ScriptAny[] args,
478         ref NativeFunctionError nfe)
479 {
480     if(args.length < 1)
481         return ScriptAny(double.nan);
482     if(!args[0].isNumber)
483         return ScriptAny(double.nan);
484     return ScriptAny(math.sinh(args[0].toValue!double));
485 }
486 
487 private ScriptAny native_Math_sqrt(Environment env,
488                                    ScriptAny* thisObj,
489                                    ScriptAny[] args,
490                                    ref NativeFunctionError nfe)
491 {
492     if(args.length < 1)
493         return ScriptAny.UNDEFINED;
494     if(!args[0].isNumber)
495         return ScriptAny.UNDEFINED;
496     return ScriptAny(math.sqrt(args[0].toValue!double));
497 }
498 
499 private ScriptAny native_Math_tan(Environment env,
500                                   ScriptAny* thisObj,
501                                   ScriptAny[] args,
502                                   ref NativeFunctionError nfe)
503 {
504     if(args.length < 1)
505         return ScriptAny(double.nan);
506     if(!args[0].isNumber)
507         return ScriptAny(double.nan);
508     return ScriptAny(math.tan(args[0].toValue!double));
509 }
510 
511 private ScriptAny native_Math_tanh(Environment env,
512                                    ScriptAny* thisObj,
513                                    ScriptAny[] args,
514                                    ref NativeFunctionError nfe)
515 {
516     if(args.length < 1)
517         return ScriptAny(double.nan);
518     if(!args[0].isNumber)
519         return ScriptAny(double.nan);
520     return ScriptAny(math.tanh(args[0].toValue!double));
521 }
522 
523 private ScriptAny native_Math_trunc(Environment env,
524                                     ScriptAny* thisObj,
525                                     ScriptAny[] args,
526                                     ref NativeFunctionError nfe)
527 {
528     if(args.length < 1)
529         return ScriptAny(double.nan);
530     if(!args[0].isNumber)
531         return ScriptAny(double.nan);
532     return ScriptAny(math.trunc(args[0].toValue!double));
533 }
534 
535 
536 /// software implementation of CLZ32 because I don't know assembly nor care to lock DMildew to a specific CPU
537 /// courtesy of https://embeddedgurus.com/state-space/2014/09/fast-deterministic-and-portable-counting-leading-zeros/
538 pragma(inline, true) 
539 uint CLZ1(uint x) 
540 {
541     static immutable ubyte[] clz_lkup = [
542         32U, 31U, 30U, 30U, 29U, 29U, 29U, 29U,
543         28U, 28U, 28U, 28U, 28U, 28U, 28U, 28U,
544         27U, 27U, 27U, 27U, 27U, 27U, 27U, 27U,
545         27U, 27U, 27U, 27U, 27U, 27U, 27U, 27U,
546         26U, 26U, 26U, 26U, 26U, 26U, 26U, 26U,
547         26U, 26U, 26U, 26U, 26U, 26U, 26U, 26U,
548         26U, 26U, 26U, 26U, 26U, 26U, 26U, 26U,
549         26U, 26U, 26U, 26U, 26U, 26U, 26U, 26U,
550         25U, 25U, 25U, 25U, 25U, 25U, 25U, 25U,
551         25U, 25U, 25U, 25U, 25U, 25U, 25U, 25U,
552         25U, 25U, 25U, 25U, 25U, 25U, 25U, 25U,
553         25U, 25U, 25U, 25U, 25U, 25U, 25U, 25U,
554         25U, 25U, 25U, 25U, 25U, 25U, 25U, 25U,
555         25U, 25U, 25U, 25U, 25U, 25U, 25U, 25U,
556         25U, 25U, 25U, 25U, 25U, 25U, 25U, 25U,
557         25U, 25U, 25U, 25U, 25U, 25U, 25U, 25U,
558         24U, 24U, 24U, 24U, 24U, 24U, 24U, 24U,
559         24U, 24U, 24U, 24U, 24U, 24U, 24U, 24U,
560         24U, 24U, 24U, 24U, 24U, 24U, 24U, 24U,
561         24U, 24U, 24U, 24U, 24U, 24U, 24U, 24U,
562         24U, 24U, 24U, 24U, 24U, 24U, 24U, 24U,
563         24U, 24U, 24U, 24U, 24U, 24U, 24U, 24U,
564         24U, 24U, 24U, 24U, 24U, 24U, 24U, 24U,
565         24U, 24U, 24U, 24U, 24U, 24U, 24U, 24U,
566         24U, 24U, 24U, 24U, 24U, 24U, 24U, 24U,
567         24U, 24U, 24U, 24U, 24U, 24U, 24U, 24U,
568         24U, 24U, 24U, 24U, 24U, 24U, 24U, 24U,
569         24U, 24U, 24U, 24U, 24U, 24U, 24U, 24U,
570         24U, 24U, 24U, 24U, 24U, 24U, 24U, 24U,
571         24U, 24U, 24U, 24U, 24U, 24U, 24U, 24U,
572         24U, 24U, 24U, 24U, 24U, 24U, 24U, 24U,
573         24U, 24U, 24U, 24U, 24U, 24U, 24U, 24U
574     ];
575     uint n;
576     if (x >= (1U << 16)) 
577     {
578         if (x >= (1U << 24)) 
579         {
580             n = 24U;
581         }
582         else 
583         {
584             n = 16U;
585         }
586     }
587     else 
588     {
589         if (x >= (1U << 8)) 
590         {
591             n = 8U;
592         }
593         else 
594         {
595             n = 0U;
596         }
597     }
598     return cast(uint)clz_lkup[x >> n] - n;
599 }