comparison scripts/general/nextpow2.m @ 33199:297fd823a953

nextpow2.m: Overhaul function for improved accuracy and Matlab compatibility (bug #65441) * nextpow2.m: Clarify documentation. Document return value of special input 0. Add input validation to exclude complex inputs. New algorithm for computing nextpow2 based on 2-output form of log2(). Use cast() to have output class match input class for Matlab compatibility. Add BIST tests. * NEWS.10.md: Announce changes to nextpow2 function.
author Rik <rik@octave.org>
date Tue, 12 Mar 2024 14:27:13 -0700
parents 2e484f9f1f18
children
comparison
equal deleted inserted replaced
33197:bee755660415 33199:297fd823a953
23 ## 23 ##
24 ######################################################################## 24 ########################################################################
25 25
26 ## -*- texinfo -*- 26 ## -*- texinfo -*-
27 ## @deftypefn {} {@var{n} =} nextpow2 (@var{x}) 27 ## @deftypefn {} {@var{n} =} nextpow2 (@var{x})
28 ## Compute the exponent for the smallest power of two larger than the input. 28 ## Compute the exponent of the next power of two not smaller than the input.
29 ## 29 ##
30 ## For each element in the input array @var{x}, return the first integer 30 ## For each element in the input array @var{x}, return the smallest integer
31 ## @var{n} such that 31 ## @var{n} such that
32 ## @tex 32 ## @tex
33 ## $2^n \ge |x|$. 33 ## $2^n \ge |x|$.
34 ## @end tex 34 ## @end tex
35 ## @ifnottex 35 ## @ifnottex
36 ## 2^n @geq{} abs (x). 36 ## @code{2^@var{n} @geq{} abs (@var{x})}.
37 ## @end ifnottex 37 ## @end ifnottex
38 ## For input elements equal to zero, return zero.
38 ## 39 ##
39 ## @seealso{pow2, log2} 40 ## @seealso{pow2, log2}
40 ## @end deftypefn 41 ## @end deftypefn
41 42
42 function n = nextpow2 (x) 43 function n = nextpow2 (x)
45 print_usage (); 46 print_usage ();
46 endif 47 endif
47 48
48 if (! isnumeric (x)) 49 if (! isnumeric (x))
49 error ("nextpow2: X must be numeric"); 50 error ("nextpow2: X must be numeric");
51 elseif (! isreal (x))
52 error ("nextpow2: X must be real");
50 endif 53 endif
51 54
52 n = ceil (log2 (abs (x))); 55 [f, n] = log2 (abs (x));
53 n(x == 0) = 0; # special case 56 n(f == 0.5)--;
57
58 if (isfloat (x))
59 idx_nan = isnan (x);
60 n(idx_nan) = x(idx_nan);
61 n(isinf (x)) = Inf;
62 else
63 n = cast (n, class (x));
64 if (intmax (x) > flintmax ())
65 n((2 .^ n) < abs (x))++;
66 endif
67 endif
54 68
55 endfunction 69 endfunction
56 70
57 71
58 %!assert (nextpow2 (16), 4) 72 %!assert (nextpow2 (16), 4)
68 %!assert (nextpow2 (0), 0) 82 %!assert (nextpow2 (0), 0)
69 %!assert (nextpow2 (1), 0) 83 %!assert (nextpow2 (1), 0)
70 %!assert (nextpow2 (Inf), Inf) 84 %!assert (nextpow2 (Inf), Inf)
71 %!assert (nextpow2 (-Inf), Inf) 85 %!assert (nextpow2 (-Inf), Inf)
72 %!assert (nextpow2 (NaN), NaN) 86 %!assert (nextpow2 (NaN), NaN)
73 %!assert (nextpow2 ([1, Inf, 3, -Inf, 9, NaN]), [0, Inf, 2, Inf, 4, NaN]) 87 %!assert (nextpow2 (NA), NA)
88 %!assert (nextpow2 ([1, Inf, 3, -Inf, 9, NaN, NA]), ...
89 %! [0, Inf, 2, Inf, 4, NaN, NA])
90
91 %!test
92 %! p = (-1074:1023).';
93 %! x = 2 .^ p;
94 %! x = [x, x + eps(x)];
95 %! x = [x, -x];
96 %! n = nextpow2 (x);
97 %! assert (n(:, 1), p);
98 %! assert (n(:, 3), p);
99 %! assert (n(:, 2), p + 1);
100 %! assert (n(:, 4), p + 1);
101
102 %!assert (nextpow2 (realmax ()), 1024)
103 %!assert (nextpow2 (-realmax ()), 1024)
104
105 %!test
106 %! p = single (-149:127).';
107 %! x = 2 .^ p;
108 %! x = [x, x + eps(x)];
109 %! x = [x, -x];
110 %! n = nextpow2 (x);
111 %! assert (n(:, 1), p);
112 %! assert (n(:, 3), p);
113 %! assert (n(:, 2), p + 1);
114 %! assert (n(:, 4), p + 1);
115
116 %!assert (nextpow2 (realmax ('single')), single (128))
117 %!assert (nextpow2 (-realmax ('single')), single (128))
118
119 %!test
120 %! p = int32 (0:30).';
121 %! x = 2 .^ p;
122 %! x = [x, x + 1];
123 %! x = [x, -x];
124 %! n = nextpow2 (x);
125 %! assert (n(:, 1), p);
126 %! assert (n(:, 3), p);
127 %! assert (n(:, 2), p + 1);
128 %! assert (n(:, 4), p + 1);
129
130 %!assert (nextpow2 (int32 (0)), int32 (0))
131 %!assert (nextpow2 (intmin ('int32')), int32 (31))
132 %!assert (nextpow2 (intmax ('int32')), int32 (31))
133
134 %!assert (nextpow2 (uint32 (0)), uint32 (0))
135 %!assert (nextpow2 (intmax ('uint32')), uint32 (32))
136
137 %!test
138 %! p = int64 (0:62).';
139 %! x = 2 .^ p;
140 %! x = [x, x + 1];
141 %! x = [x, -x];
142 %! n = nextpow2 (x);
143 %! assert (n(:, 1), p);
144 %! assert (n(:, 3), p);
145 %! assert (n(:, 2), p + 1);
146 %! assert (n(:, 4), p + 1);
147
148 %!assert (nextpow2 (int64 (0)), int64 (0))
149 %!assert (nextpow2 (intmin ('int64')), int64 (63))
150 %!assert (nextpow2 (intmax ('int64')), int64 (63))
151
152 %!assert (nextpow2 (uint64 (0)), uint64 (0))
153 %!assert (nextpow2 (intmax ('uint64')), uint64 (64))
74 154
75 ## Test input validation 155 ## Test input validation
76 %!error <Invalid call> nextpow2 () 156 %!error <Invalid call> nextpow2 ()
77 %!error <X must be numeric> nextpow2 ("t") 157 %!error <X must be numeric> nextpow2 ("t")
158 %!error <X must be real> nextpow2 (1 + 2i)