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