GNU Octave  8.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
bitfcns.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 2004-2023 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING. If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 #if defined (HAVE_CONFIG_H)
27 # include "config.h"
28 #endif
29 
30 #include <limits>
31 
32 #include "str-vec.h"
33 #include "quit.h"
34 
35 #include "defun.h"
36 #include "error.h"
37 #include "ov.h"
38 #include "ov-uint64.h"
39 #include "ov-uint32.h"
40 #include "ov-uint16.h"
41 #include "ov-uint8.h"
42 #include "ov-int64.h"
43 #include "ov-int32.h"
44 #include "ov-int16.h"
45 #include "ov-int8.h"
46 #include "ov-float.h"
47 #include "ov-scalar.h"
48 #include "ov-re-mat.h"
49 #include "ov-bool.h"
50 
51 #include <functional>
52 
53 #if ! defined (HAVE_CXX_BITWISE_OP_TEMPLATES)
55 
56 template <typename T>
57 struct bit_and
58 {
59 public:
60  T operator() (const T& op1, const T& op2) const { return (op1 & op2); }
61 };
62 
63 template <typename T>
64 struct bit_or
65 {
66 public:
67  T operator() (const T& op1, const T& op2) const { return (op1 | op2); }
68 };
69 
70 template <typename T>
71 struct bit_xor
72 {
73 public:
74  T operator() (const T& op1, const T& op2) const { return (op1 ^ op2); }
75 };
76 
78 #endif
79 
81 
82 template <typename OP, typename T>
84 bitopxx (const OP& op, const std::string& fname,
85  const Array<T>& x, const Array<T>& y)
86 {
87  int nelx = x.numel ();
88  int nely = y.numel ();
89 
90  bool is_scalar_op = (nelx == 1 || nely == 1);
91 
92  dim_vector dvx = x.dims ();
93  dim_vector dvy = y.dims ();
94 
95  bool is_array_op = (dvx == dvy);
96 
97  if (! is_array_op && ! is_scalar_op)
98  error ("%s: size of X and Y must match, or one operand must be a scalar",
99  fname.c_str ());
100 
101  Array<T> result;
102 
103  if (nelx != 1)
104  result.resize (dvx);
105  else
106  result.resize (dvy);
107 
108  for (int i = 0; i < nelx; i++)
109  if (is_scalar_op)
110  for (int k = 0; k < nely; k++)
111  result(i+k) = op (x(i), y(k));
112  else
113  result(i) = op (x(i), y(i));
114 
115  return result;
116 }
117 
118 // Trampoline function, instantiates the proper template above, with
119 // reflective information hardwired. We can't hardwire this information
120 // in Fbitxxx DEFUNs below, because at that moment, we still don't have
121 // information about which integer types we need to instantiate.
122 template <typename T>
124 bitopx (const std::string& fname, const Array<T>& x, const Array<T>& y)
125 {
126  if (fname == "bitand")
127  return bitopxx (std::bit_and<T>(), fname, x, y);
128  if (fname == "bitor")
129  return bitopxx (std::bit_or<T>(), fname, x, y);
130 
131  //else (fname == "bitxor")
132  return bitopxx (std::bit_xor<T>(), fname, x, y);
133 }
134 
135 static inline int
137 {
138  return (arg.class_name () != octave_scalar::static_class_name ()
141 }
142 
143 static inline int
145 {
146  return arg.class_name () == octave_bool::static_class_name ();
147 }
148 
149 static inline int
151 {
153 }
154 
156 bitop (const std::string& fname, const octave_value_list& args)
157 {
158  if (args.length () != 2)
159  print_usage ();
160 
161  octave_value retval;
162 
163  if (args(0).class_name () == octave_scalar::static_class_name ()
164  || args(0).class_name () == octave_float_scalar::static_class_name ()
165  || args(0).class_name () == octave_bool::static_class_name ()
166  || args(1).class_name () == octave_scalar::static_class_name ()
167  || args(1).class_name () == octave_float_scalar::static_class_name ()
168  || args(1).class_name () == octave_bool::static_class_name ())
169  {
170  bool arg0_is_int = bitop_arg_is_int (args(0));
171  bool arg1_is_int = bitop_arg_is_int (args(1));
172 
173  bool arg0_is_bool = bitop_arg_is_bool (args(0));
174  bool arg1_is_bool = bitop_arg_is_bool (args(1));
175 
176  bool arg0_is_float = bitop_arg_is_float (args(0));
177  bool arg1_is_float = bitop_arg_is_float (args(1));
178 
179  if (! (arg0_is_int || arg1_is_int))
180  {
181  if (arg0_is_bool && arg1_is_bool)
182  {
183  boolNDArray x (args(0).bool_array_value ());
184  boolNDArray y (args(1).bool_array_value ());
185 
186  retval = bitopx (fname, x, y).bool_array_value ();
187  }
188  else if (arg0_is_float && arg1_is_float)
189  {
190  uint64NDArray x (args(0).float_array_value ());
191  uint64NDArray y (args(1).float_array_value ());
192 
193  retval = bitopx (fname, x, y).float_array_value ();
194  }
195  else if (! (arg0_is_float || arg1_is_float))
196  {
197  uint64NDArray x (args(0).array_value ());
198  uint64NDArray y (args(1).array_value ());
199 
200  retval = bitopx (fname, x, y).array_value ();
201  }
202  else
203  {
204  int p = (arg0_is_float ? 1 : 0);
205  int q = (arg0_is_float ? 0 : 1);
206 
207  uint64NDArray x (args(p).array_value ());
208  uint64NDArray y (args(q).float_array_value ());
209 
210  retval = bitopx (fname, x, y).float_array_value ();
211  }
212  }
213  else
214  {
215  int p = (arg0_is_int ? 1 : 0);
216  int q = (arg0_is_int ? 0 : 1);
217 
218  NDArray dx = args(p).array_value ();
219 
220  if (args(q).type_id () == octave_uint64_matrix::static_type_id ()
221  || args(q).type_id () == octave_uint64_scalar::static_type_id ())
222  {
223  uint64NDArray x (dx);
224  uint64NDArray y = args(q).uint64_array_value ();
225 
226  retval = bitopx (fname, x, y);
227  }
228  else if (args(q).type_id () == octave_uint32_matrix::static_type_id ()
229  || args(q).type_id () == octave_uint32_scalar::static_type_id ())
230  {
231  uint32NDArray x (dx);
232  uint32NDArray y = args(q).uint32_array_value ();
233 
234  retval = bitopx (fname, x, y);
235  }
236  else if (args(q).type_id () == octave_uint16_matrix::static_type_id ()
237  || args(q).type_id () == octave_uint16_scalar::static_type_id ())
238  {
239  uint16NDArray x (dx);
240  uint16NDArray y = args(q).uint16_array_value ();
241 
242  retval = bitopx (fname, x, y);
243  }
244  else if (args(q).type_id () == octave_uint8_matrix::static_type_id ()
245  || args(q).type_id () == octave_uint8_scalar::static_type_id ())
246  {
247  uint8NDArray x (dx);
248  uint8NDArray y = args(q).uint8_array_value ();
249 
250  retval = bitopx (fname, x, y);
251  }
252  else if (args(q).type_id () == octave_int64_matrix::static_type_id ()
253  || args(q).type_id () == octave_int64_scalar::static_type_id ())
254  {
255  int64NDArray x (dx);
256  int64NDArray y = args(q).int64_array_value ();
257 
258  retval = bitopx (fname, x, y);
259  }
260  else if (args(q).type_id () == octave_int32_matrix::static_type_id ()
261  || args(q).type_id () == octave_int32_scalar::static_type_id ())
262  {
263  int32NDArray x (dx);
264  int32NDArray y = args(q).int32_array_value ();
265 
266  retval = bitopx (fname, x, y);
267  }
268  else if (args(q).type_id () == octave_int16_matrix::static_type_id ()
269  || args(q).type_id () == octave_int16_scalar::static_type_id ())
270  {
271  int16NDArray x (dx);
272  int16NDArray y = args(q).int16_array_value ();
273 
274  retval = bitopx (fname, x, y);
275  }
276  else if (args(q).type_id () == octave_int8_matrix::static_type_id ()
277  || args(q).type_id () == octave_int8_scalar::static_type_id ())
278  {
279  int8NDArray x (dx);
280  int8NDArray y = args(q).int8_array_value ();
281 
282  retval = bitopx (fname, x, y);
283  }
284  else
285  error ("%s: invalid operand type", fname.c_str ());
286  }
287  }
288  else if (args(0).class_name () == args(1).class_name ())
289  {
290  if (args(0).type_id () == octave_uint64_matrix::static_type_id ()
291  || args(0).type_id () == octave_uint64_scalar::static_type_id ())
292  {
293  uint64NDArray x = args(0).uint64_array_value ();
294  uint64NDArray y = args(1).uint64_array_value ();
295 
296  retval = bitopx (fname, x, y);
297  }
298  else if (args(0).type_id () == octave_uint32_matrix::static_type_id ()
299  || args(0).type_id () == octave_uint32_scalar::static_type_id ())
300  {
301  uint32NDArray x = args(0).uint32_array_value ();
302  uint32NDArray y = args(1).uint32_array_value ();
303 
304  retval = bitopx (fname, x, y);
305  }
306  else if (args(0).type_id () == octave_uint16_matrix::static_type_id ()
307  || args(0).type_id () == octave_uint16_scalar::static_type_id ())
308  {
309  uint16NDArray x = args(0).uint16_array_value ();
310  uint16NDArray y = args(1).uint16_array_value ();
311 
312  retval = bitopx (fname, x, y);
313  }
314  else if (args(0).type_id () == octave_uint8_matrix::static_type_id ()
315  || args(0).type_id () == octave_uint8_scalar::static_type_id ())
316  {
317  uint8NDArray x = args(0).uint8_array_value ();
318  uint8NDArray y = args(1).uint8_array_value ();
319 
320  retval = bitopx (fname, x, y);
321  }
322  else if (args(0).type_id () == octave_int64_matrix::static_type_id ()
323  || args(0).type_id () == octave_int64_scalar::static_type_id ())
324  {
325  int64NDArray x = args(0).int64_array_value ();
326  int64NDArray y = args(1).int64_array_value ();
327 
328  retval = bitopx (fname, x, y);
329  }
330  else if (args(0).type_id () == octave_int32_matrix::static_type_id ()
331  || args(0).type_id () == octave_int32_scalar::static_type_id ())
332  {
333  int32NDArray x = args(0).int32_array_value ();
334  int32NDArray y = args(1).int32_array_value ();
335 
336  retval = bitopx (fname, x, y);
337  }
338  else if (args(0).type_id () == octave_int16_matrix::static_type_id ()
339  || args(0).type_id () == octave_int16_scalar::static_type_id ())
340  {
341  int16NDArray x = args(0).int16_array_value ();
342  int16NDArray y = args(1).int16_array_value ();
343 
344  retval = bitopx (fname, x, y);
345  }
346  else if (args(0).type_id () == octave_int8_matrix::static_type_id ()
347  || args(0).type_id () == octave_int8_scalar::static_type_id ())
348  {
349  int8NDArray x = args(0).int8_array_value ();
350  int8NDArray y = args(1).int8_array_value ();
351 
352  retval = bitopx (fname, x, y);
353  }
354  else
355  error ("%s: invalid operand type", fname.c_str ());
356  }
357  else
358  error ("%s: must have matching operand types", fname.c_str ());
359 
360  return retval;
361 }
362 
363 DEFUN (bitand, args, ,
364  doc: /* -*- texinfo -*-
365 @deftypefn {} {@var{z} =} bitand (@var{x}, @var{y})
366 Return the bitwise AND of non-negative integers.
367 
368 @var{x}, @var{y} must be in the range [0,intmax]
369 @seealso{bitor, bitxor, bitset, bitget, bitcmp, bitshift, intmax, flintmax}
370 @end deftypefn */)
371 {
372  return bitop ("bitand", args);
373 }
374 
375 /*
376 %!# Function bitand is tested as part of bitxor BIST tests
377 */
378 
379 DEFUN (bitor, args, ,
380  doc: /* -*- texinfo -*-
381 @deftypefn {} {@var{z} =} bitor (@var{x}, @var{y})
382 Return the bitwise OR of non-negative integers @var{x} and @var{y}.
383 
384 @seealso{bitor, bitxor, bitset, bitget, bitcmp, bitshift, intmax, flintmax}
385 @end deftypefn */)
386 {
387  return bitop ("bitor", args);
388 }
389 
390 /*
391 %!# Function bitor is tested as part of bitxor BIST tests
392 */
393 
394 DEFUN (bitxor, args, ,
395  doc: /* -*- texinfo -*-
396 @deftypefn {} {@var{z} =} bitxor (@var{x}, @var{y})
397 Return the bitwise XOR of non-negative integers @var{x} and @var{y}.
398 
399 @seealso{bitand, bitor, bitset, bitget, bitcmp, bitshift, intmax, flintmax}
400 @end deftypefn */)
401 {
402  return bitop ("bitxor", args);
403 }
404 
405 /*
406 %!assert (bitand (true, false), false)
407 %!assert (bitor (true, false), true)
408 %!assert (bitxor (true, false), true)
409 
410 %!assert (bitand (true, true), true)
411 %!assert (bitor (true, true), true)
412 %!assert (bitxor (true, true), false)
413 
414 %!assert (bitand (true, 5), 1)
415 
416 %!assert (bitand (true, false), false)
417 %!assert (bitand (true, true), true)
418 %!assert (bitand (true, false), false)
419 %!assert (bitand (true, false), false)
420 
421 ## Test idx_arg.length () == 0
422 %!error <size of X and Y must match> bitand ([0 0 0], [1 0])
423 %!error <size of X and Y must match> bitand ([0; 0; 0], [0 0 0])
424 */
425 
426 template <typename T>
427 static int64_t
429 {
430  return (static_cast<int64_t> (1) << std::numeric_limits<T>::digits) - 1;
431 }
432 
433 static int64_t
434 bitshift (double a, int n, int64_t mask)
435 {
436  // In the name of bug-for-bug compatibility.
437  if (a < 0)
438  return -bitshift (-a, n, mask);
439 
440  if (n > 0)
441  return (static_cast<int64_t> (a) << n) & mask;
442  else if (n < 0)
443  return (static_cast<int64_t> (a) >> -n) & mask;
444  else
445  return static_cast<int64_t> (a) & mask;
446 }
447 
448 static int64_t
449 bitshift (float a, int n, int64_t mask)
450 {
451  // In the name of bug-for-bug compatibility.
452  if (a < 0)
453  return -bitshift (-a, n, mask);
454 
455  if (n > 0)
456  return (static_cast<int64_t> (a) << n) & mask;
457  else if (n < 0)
458  return (static_cast<int64_t> (a) >> -n) & mask;
459  else
460  return static_cast<int64_t> (a) & mask;
461 }
462 
463 // Note that the bitshift operators are undefined if shifted by more
464 // bits than in the type, so we need to test for the size of the
465 // shift.
466 
467 #define DO_BITSHIFT(T) \
468  double d1, d2; \
469  \
470  if (! n.all_integers (d1, d2)) \
471  error ("bitshift: K must be a scalar or array of integers"); \
472  \
473  int m_nel = m.numel (); \
474  int n_nel = n.numel (); \
475  \
476  bool is_scalar_op = (m_nel == 1 || n_nel == 1); \
477  \
478  dim_vector m_dv = m.dims (); \
479  dim_vector n_dv = n.dims (); \
480  \
481  bool is_array_op = (m_dv == n_dv); \
482  \
483  if (! is_array_op && ! is_scalar_op) \
484  error ("bitshift: size of A and N must match, or one operand must be a scalar"); \
485  \
486  T ## NDArray result; \
487  \
488  if (m_nel != 1) \
489  result.resize (m_dv); \
490  else \
491  result.resize (n_dv); \
492  \
493  for (int i = 0; i < m_nel; i++) \
494  if (is_scalar_op) \
495  for (int k = 0; k < n_nel; k++) \
496  if (static_cast<int> (n(k)) >= bits_in_type) \
497  result(i+k) = 0; \
498  else \
499  result(i+k) = bitshift (m(i), static_cast<int> (n(k)), mask); \
500  else \
501  if (static_cast<int> (n(i)) >= bits_in_type) \
502  result(i) = 0; \
503  else \
504  result(i) = bitshift (m(i), static_cast<int> (n(i)), mask); \
505  \
506  retval = result;
507 
508 #define DO_UBITSHIFT(T, N) \
509  do \
510  { \
511  int bits_in_type = octave_ ## T :: nbits (); \
512  T ## NDArray m = m_arg.T ## _array_value (); \
513  octave_ ## T mask = octave_ ## T::max (); \
514  if ((N) < bits_in_type) \
515  mask = bitshift (mask, (N) - bits_in_type); \
516  else if ((N) < 1) \
517  mask = 0; \
518  DO_BITSHIFT (T); \
519  } \
520  while (0)
521 
522 #define DO_SBITSHIFT(T, N) \
523  do \
524  { \
525  int bits_in_type = octave_ ## T :: nbits (); \
526  T ## NDArray m = m_arg.T ## _array_value (); \
527  octave_ ## T mask = octave_ ## T::max (); \
528  if ((N) < bits_in_type) \
529  mask = bitshift (mask, (N) - bits_in_type); \
530  else if ((N) < 1) \
531  mask = 0; \
532  /* FIXME: 2's complement only? */ \
533  mask = mask | octave_ ## T :: min (); \
534  DO_BITSHIFT (T); \
535  } \
536  while (0)
537 
538 DEFUN (bitshift, args, ,
539  doc: /* -*- texinfo -*-
540 @deftypefn {} {@var{B} =} bitshift (@var{A}, @var{k})
541 @deftypefnx {} {@var{B} =} bitshift (@var{A}, @var{k}, @var{n})
542 Return a @var{k} bit shift of @var{n}-digit unsigned integers in @var{A}.
543 
544 A positive @var{k} leads to a left shift; A negative value to a right shift.
545 
546 If @var{n} is omitted it defaults to 64. @var{n} must be in the range [1,64].
547 
548 @example
549 @group
550 bitshift (eye (3), 1)
551 @result{}
552 @group
553 2 0 0
554 0 2 0
555 0 0 2
556 @end group
557 
558 bitshift (10, [-2, -1, 0, 1, 2])
559 @result{} 2 5 10 20 40
560 @c FIXME: restore this example when third arg is allowed to be an array.
561 @c
562 @c
563 @c bitshift ([1, 10], 2, [3,4])
564 @c @result{} 4 8
565 @end group
566 @end example
567 @seealso{bitand, bitor, bitxor, bitset, bitget, bitcmp, intmax, flintmax}
568 @end deftypefn */)
569 {
570  int nargin = args.length ();
571 
572  if (nargin < 2 || nargin > 3)
573  print_usage ();
574 
575  NDArray n = args(1).xarray_value ("bitshift: K must be a scalar or array of integers");
576 
577  int nbits = 64;
578 
579  if (nargin == 3)
580  {
581  // FIXME: for compatibility, we should accept an array or a scalar
582  // as the third argument.
583  if (args(2).numel () > 1)
584  error ("bitshift: N must be a scalar integer");
585 
586  nbits = args(2).xint_value ("bitshift: N must be an integer");
587 
588  if (nbits < 0)
589  error ("bitshift: N must be positive");
590  }
591 
592  octave_value retval;
593 
594  octave_value m_arg = args(0);
595  std::string cname = m_arg.class_name ();
596 
597  if (cname == "double")
598  {
599  static const int bits_in_mantissa
600  = std::numeric_limits<double>::digits;
601 
602  nbits = (nbits < bits_in_mantissa ? nbits : bits_in_mantissa);
603  int64_t mask = max_mantissa_value<double> ();
604  if (nbits < bits_in_mantissa)
605  mask = mask >> (bits_in_mantissa - nbits);
606  int bits_in_type = sizeof (double)
607  * std::numeric_limits<unsigned char>::digits;
608  NDArray m = m_arg.array_value ();
609  DO_BITSHIFT ();
610  }
611  else if (cname == "uint8")
612  DO_UBITSHIFT (uint8, nbits < 8 ? nbits : 8);
613  else if (cname == "uint16")
614  DO_UBITSHIFT (uint16, nbits < 16 ? nbits : 16);
615  else if (cname == "uint32")
616  DO_UBITSHIFT (uint32, nbits < 32 ? nbits : 32);
617  else if (cname == "uint64")
618  DO_UBITSHIFT (uint64, nbits < 64 ? nbits : 64);
619  else if (cname == "int8")
620  DO_SBITSHIFT (int8, nbits < 8 ? nbits : 8);
621  else if (cname == "int16")
622  DO_SBITSHIFT (int16, nbits < 16 ? nbits : 16);
623  else if (cname == "int32")
624  DO_SBITSHIFT (int32, nbits < 32 ? nbits : 32);
625  else if (cname == "int64")
626  DO_SBITSHIFT (int64, nbits < 64 ? nbits : 64);
627  else if (cname == "single")
628  {
629  static const int bits_in_mantissa
630  = std::numeric_limits<float>::digits;
631  nbits = (nbits < bits_in_mantissa ? nbits : bits_in_mantissa);
632  int64_t mask = max_mantissa_value<float> ();
633  if (nbits < bits_in_mantissa)
634  mask = mask >> (bits_in_mantissa - nbits);
635  int bits_in_type = sizeof (float)
636  * std::numeric_limits<unsigned char>::digits;
637  FloatNDArray m = m_arg.float_array_value ();
638  DO_BITSHIFT (Float);
639  }
640  else
641  error ("bitshift: not defined for %s objects", cname.c_str ());
642 
643  return retval;
644 }
645 
646 /*
647 %!assert (bitshift (uint8 (16), 1), uint8 ( 32))
648 %!assert (bitshift (uint16 (16), 2), uint16 ( 64))
649 %!assert (bitshift (uint32 (16), 3), uint32 (128))
650 %!assert (bitshift (uint64 (16), 4), uint64 (256))
651 %!assert (bitshift (uint8 (255), 1), uint8 (254))
652 
653 %!error <K must be a scalar or array of integers> bitshift (16, 1.5)
654 %!error bitshift (16, {1})
655 %!error <N must be a scalar integer> bitshift (10, [-2 -1 0 1 2], [1 1 1 1 1])
656 %!error <N must be positive> bitshift (10, [-2 -1 0 1 2], -1)
657 */
658 
659 DEFUN (flintmax, args, ,
660  doc: /* -*- texinfo -*-
661 @deftypefn {} {@var{Imax} =} flintmax ()
662 @deftypefnx {} {@var{Imax} =} flintmax ("double")
663 @deftypefnx {} {@var{Imax} =} flintmax ("single")
664 @deftypefnx {} {@var{Imax} =} flintmax (@var{var})
665 Return the largest integer that can be represented consecutively in a
666 floating point value.
667 
668 The input is either a string specifying a floating point type, or it is an
669 existing floating point variable @var{var}.
670 
671 The default type is @qcode{"double"}, but @qcode{"single"} is a valid option.
672 On IEEE 754 compatible systems, @code{flintmax} is @w{@math{2^{53}}} for
673 @qcode{"double"} and @w{@math{2^{24}}} for @qcode{"single"}.
674 
675 Example Code - query an existing variable
676 
677 @example
678 @group
679 x = single (1);
680 flintmax (x)
681  @result{} 16777216
682 @end group
683 @end example
684 
685 @seealso{intmax, realmax, realmin}
686 @end deftypefn */)
687 {
688  int nargin = args.length ();
689 
690  if (nargin > 1)
691  print_usage ();
692 
693  std::string cname = "double";
694  if (nargin == 1)
695  {
696  if (args(0).is_string ())
697  cname = args(0).string_value ();
698  else if (args(0).isfloat ())
699  cname = args(0).class_name ();
700  else
701  error ("intmin: argument must be a string or floating point variable");
702  }
703 
704  if (cname == "double")
705  return ovl (static_cast<double> (max_mantissa_value<double> () + 1));
706  else if (cname == "single")
707  return ovl (static_cast<float> (max_mantissa_value<float> () + 1));
708  else
709  error ("flintmax: not defined for class '%s'", cname.c_str ());
710 }
711 
712 /*
713 %!assert (flintmax (), 2^53)
714 %!assert (flintmax ("double"), 2^53)
715 %!assert (flintmax ("single"), single (2^24))
716 
717 %!test
718 %! x = single (1);
719 %! assert (flintmax (x), single (16777216));
720 
721 %!error flintmax ("double", 0)
722 %!error <must be a string or floating point variable> flintmax (int8 (1))
723 %!error <not defined for class 'int8'> flintmax ("int8")
724 %!error <not defined for class 'char'> flintmax ("char")
725 */
726 
727 DEFUN (intmax, args, ,
728  doc: /* -*- texinfo -*-
729 @deftypefn {} {@var{Imax} =} intmax ()
730 @deftypefnx {} {@var{Imax} =} intmax ("@var{type}")
731 @deftypefnx {} {@var{Imax} =} intmax (@var{var})
732 Return the largest integer that can be represented by a specific integer type.
733 
734 The input is either a string @qcode{"@var{type}"} specifying an integer type,
735 or it is an existing integer variable @var{var}.
736 
737 Possible values for @var{type} are
738 
739 @table @asis
740 @item @qcode{"int8"}
741 signed 8-bit integer.
742 
743 @item @qcode{"int16"}
744 signed 16-bit integer.
745 
746 @item @qcode{"int32"}
747 signed 32-bit integer.
748 
749 @item @qcode{"int64"}
750 signed 64-bit integer.
751 
752 @item @qcode{"uint8"}
753 unsigned 8-bit integer.
754 
755 @item @qcode{"uint16"}
756 unsigned 16-bit integer.
757 
758 @item @qcode{"uint32"}
759 unsigned 32-bit integer.
760 
761 @item @qcode{"uint64"}
762 unsigned 64-bit integer.
763 @end table
764 
765 The default for @var{type} is @qcode{"int32"}.
766 
767 Example Code - query an existing variable
768 
769 @example
770 @group
771 x = int8 (1);
772 intmax (x)
773  @result{} 127
774 @end group
775 @end example
776 
777 @seealso{intmin, flintmax}
778 @end deftypefn */)
779 {
780  int nargin = args.length ();
781 
782  if (nargin > 1)
783  print_usage ();
784 
785  std::string cname = "int32";
786  if (nargin == 1)
787  {
788  if (args(0).is_string ())
789  cname = args(0).string_value ();
790  else if (args(0).isinteger ())
791  cname = args(0).class_name ();
792  else
793  error ("intmax: argument must be a string or integer variable");
794  }
795 
796  octave_value retval;
797 
798  if (cname == "uint8")
800  else if (cname == "uint16")
802  else if (cname == "uint32")
804  else if (cname == "uint64")
806  else if (cname == "int8")
808  else if (cname == "int16")
810  else if (cname == "int32")
812  else if (cname == "int64")
814  else
815  error ("intmax: not defined for '%s' objects", cname.c_str ());
816 
817  return retval;
818 }
819 
820 /*
821 %!assert (intmax (), int32 (2^31 - 1))
822 %!assert (intmax ("int8"), int8 (2^7 - 1))
823 %!assert (intmax ("uint8"), uint8 (2^8 - 1))
824 %!assert (intmax ("int16"), int16 (2^15 - 1))
825 %!assert (intmax ("uint16"), uint16 (2^16 - 1))
826 %!assert (intmax ("int32"), int32 (2^31 - 1))
827 %!assert (intmax ("uint32"), uint32 (2^32 - 1))
828 %!assert (intmax ("int64"), int64 (2^63 - 1))
829 %!assert (intmax ("uint64"), uint64 (2^64 - 1))
830 
831 %!test
832 %! x = int8 (1);
833 %! assert (intmax (x), int8 (127));
834 
835 %!error intmax ("int32", 0)
836 %!error <must be a string or integer variable> intmax (1.0)
837 %!error <not defined for 'double' objects> intmax ("double")
838 %!error <not defined for 'char' objects> intmax ("char")
839 */
840 
841 DEFUN (intmin, args, ,
842  doc: /* -*- texinfo -*-
843 @deftypefn {} {@var{Imin} =} intmin ()
844 @deftypefnx {} {@var{Imin} =} intmin ("@var{type}")
845 @deftypefnx {} {@var{Imin} =} intmin (@var{var})
846 Return the smallest integer that can be represented by a specific integer type.
847 
848 The input is either a string @qcode{"@var{type}"} specifying an integer type,
849 or it is an existing integer variable @var{var}.
850 
851 Possible values for @var{type} are
852 
853 @table @asis
854 @item @qcode{"int8"}
855 signed 8-bit integer.
856 
857 @item @qcode{"int16"}
858 signed 16-bit integer.
859 
860 @item @qcode{"int32"}
861 signed 32-bit integer.
862 
863 @item @qcode{"int64"}
864 signed 64-bit integer.
865 
866 @item @qcode{"uint8"}
867 unsigned 8-bit integer.
868 
869 @item @qcode{"uint16"}
870 unsigned 16-bit integer.
871 
872 @item @qcode{"uint32"}
873 unsigned 32-bit integer.
874 
875 @item @qcode{"uint64"}
876 unsigned 64-bit integer.
877 @end table
878 
879 The default for @var{type} is @qcode{"int32"}.
880 
881 Example Code - query an existing variable
882 
883 @example
884 @group
885 x = int8 (1);
886 intmin (x)
887  @result{} -128
888 @end group
889 @end example
890 
891 @seealso{intmax, flintmax}
892 @end deftypefn */)
893 {
894  int nargin = args.length ();
895 
896  if (nargin > 1)
897  print_usage ();
898 
899  std::string cname = "int32";
900  if (nargin == 1)
901  {
902  if (args(0).is_string ())
903  cname = args(0).string_value ();
904  else if (args(0).isinteger ())
905  cname = args(0).class_name ();
906  else
907  error ("intmin: argument must be a string or integer variable");
908  }
909 
910  octave_value retval;
911 
912  if (cname == "uint8")
914  else if (cname == "uint16")
916  else if (cname == "uint32")
918  else if (cname == "uint64")
920  else if (cname == "int8")
922  else if (cname == "int16")
924  else if (cname == "int32")
926  else if (cname == "int64")
928  else
929  error ("intmin: not defined for '%s' objects", cname.c_str ());
930 
931  return retval;
932 }
933 
934 /*
935 %!assert (intmin (), int32 (-2^31))
936 %!assert (intmin ("int8"), int8 (-2^7))
937 %!assert (intmin ("uint8"), uint8 (-2^8))
938 %!assert (intmin ("int16"), int16 (-2^15))
939 %!assert (intmin ("uint16"), uint16 (-2^16))
940 %!assert (intmin ("int32"), int32 (-2^31))
941 %!assert (intmin ("uint32"), uint32 (-2^32))
942 %!assert (intmin ("int64"), int64 (-2^63))
943 %!assert (intmin ("uint64"), uint64 (-2^64))
944 
945 %!test
946 %! x = int8 (1);
947 %! assert (intmin (x), int8 (-128));
948 
949 %!error intmin ("int32", 0)
950 %!error <must be a string or integer variable> intmin (1.0)
951 %!error <not defined for 'double' objects> intmin ("double")
952 %!error <not defined for 'char' objects> intmin ("char")
953 */
954 
955 DEFUN (sizemax, args, ,
956  doc: /* -*- texinfo -*-
957 @deftypefn {} {@var{max_numel} =} sizemax ()
958 Return the largest value allowed for the size of an array.
959 
960 If Octave is compiled with 64-bit indexing, the result is of class int64,
961 otherwise it is of class int32. The maximum array size is slightly smaller
962 than the maximum value allowable for the relevant class as reported by
963 @code{intmax}.
964 @seealso{intmax}
965 @end deftypefn */)
966 {
967  if (args.length () != 0)
968  print_usage ();
969 
971 }
972 
973 /*
974 %!assert (sizemax () >= (intmax ("int32") - 1))
975 
976 %!error sizemax (0)
977 */
978 
OCTAVE_END_NAMESPACE(octave)
static int bitop_arg_is_float(const octave_value &arg)
Definition: bitfcns.cc:150
octave_value bitop(const std::string &fname, const octave_value_list &args)
Definition: bitfcns.cc:156
octave_value bitopxx(const OP &op, const std::string &fname, const Array< T > &x, const Array< T > &y)
Definition: bitfcns.cc:84
static int bitop_arg_is_bool(const octave_value &arg)
Definition: bitfcns.cc:144
octave_value bitopx(const std::string &fname, const Array< T > &x, const Array< T > &y)
Definition: bitfcns.cc:124
#define DO_BITSHIFT(T)
Definition: bitfcns.cc:467
#define DO_UBITSHIFT(T, N)
Definition: bitfcns.cc:508
#define DO_SBITSHIFT(T, N)
Definition: bitfcns.cc:522
static int64_t max_mantissa_value()
Definition: bitfcns.cc:428
static int64_t bitshift(double a, int n, int64_t mask)
Definition: bitfcns.cc:434
static int bitop_arg_is_int(const octave_value &arg)
Definition: bitfcns.cc:136
charNDArray max(char d, const charNDArray &m)
Definition: chNDArray.cc:230
charNDArray min(char d, const charNDArray &m)
Definition: chNDArray.cc:207
OCTARRAY_OVERRIDABLE_FUNC_API octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:414
OCTARRAY_OVERRIDABLE_FUNC_API const dim_vector & dims(void) const
Return a const-reference so that dims ()(i) works efficiently.
Definition: Array.h:503
OCTARRAY_API void resize(const dim_vector &dv, const T &rfv)
Size of the specified dimension.
Definition: Array-base.cc:1032
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:94
static OCTAVE_API octave_idx_type dim_max(void)
Definition: dim-vector.cc:44
static std::string static_class_name(void)
Definition: ov-bool.h:261
static std::string static_class_name(void)
Definition: ov-float.h:278
static std::string static_class_name(void)
Definition: ov-scalar.h:281
static int static_type_id(void)
Definition: ov-intx.h:386
static int static_type_id(void)
Definition: ov-intx.h:699
octave_idx_type length(void) const
Definition: ovl.h:113
Array< octave_value > array_value(void) const
Definition: ovl.h:90
boolNDArray bool_array_value(bool warn=false) const
Definition: ov.h:936
std::string class_name(void) const
Definition: ov.h:1454
NDArray array_value(bool frc_str_conv=false) const
Definition: ov.h:904
FloatNDArray float_array_value(bool frc_str_conv=false) const
Definition: ov.h:907
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
OCTINTERP_API void print_usage(void)
Definition: defun-int.h:72
#define DEFUN(name, args_name, nargout_name, doc)
Macro to define a builtin function.
Definition: defun.h:56
void error(const char *fmt,...)
Definition: error.cc:979
static uint64_t flintmax(void)
Definition: lex.cc:6019
bool isinteger(double x)
Definition: lo-mappers.h:225
F77_RET_T const F77_DBLE * x
T octave_idx_type m
Definition: mx-inlines.cc:773
octave_idx_type n
Definition: mx-inlines.cc:753
octave_int< uint32_t > octave_uint32
octave_int< int32_t > octave_int32
octave_int< int16_t > octave_int16
octave_int< int8_t > octave_int8
octave_int< int64_t > octave_int64
octave_int< uint64_t > octave_uint64
octave_int< uint16_t > octave_uint16
octave_int< uint8_t > octave_uint8
T::size_type numel(const T &str)
Definition: oct-string.cc:71
return octave_value(v1.char_array_value() . concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string()) ? '\'' :'"'))
octave_value_list ovl(const OV_Args &... args)
Construct an octave_value_list with less typing.
Definition: ovl.h:211
T operator()(const T &op1, const T &op2) const
Definition: bitfcns.cc:60
T operator()(const T &op1, const T &op2) const
Definition: bitfcns.cc:67
T operator()(const T &op1, const T &op2) const
Definition: bitfcns.cc:74