view libinterp/corefcn/bitfcns.cc @ 19010:3fb030666878 draft default tip dspies

Added special-case logical-indexing function * logical-index.h (New file) : Logical-indexing function. May be called on octave_value types via call_bool_index * nz-iterators.h : Add base-class nz_iterator for iterator types. Array has template bool for whether to internally store row-col or compute on the fly Add skip_ahead method which skips forward to the next nonzero after its argument Add flat_index for computing octave_idx_type index of current position (with assertion failure in the case of overflow) Move is_zero to separate file * ov-base-diag.cc, ov-base-mat.cc, ov-base-sparse.cc, ov-perm.cc (do_index_op): Add call to call_bool_index in logical-index.h * Array.h : Move forward-declaration for array_iterator to separate header file * dim-vector.cc (dim_max): Refers to idx-bounds.h (max_idx) * array-iter-decl.h (New file): Header file for forward declaration of array-iterator * direction.h : Add constants fdirc and bdirc to avoid having to reconstruct them * dv-utils.h, dv-utils.cc (New files) : Utility functions for querying and constructing dim-vectors * idx-bounds.h (New file) : Utility constants and functions for determining whether things will overflow the maximum allowed bounds * interp-idx.h (New function : to_flat_idx) : Converts row-col pair to linear index of octave_idx_type * is-zero.h (New file) : Function for determining whether an element is zero * logical-index.tst : Add tests for correct return-value dimensions and large sparse matrix behavior
author David Spies <dnspies@gmail.com>
date Fri, 25 Jul 2014 13:39:31 -0600
parents 6113e0c6920b
children
line wrap: on
line source

/*

Copyright (C) 2004-2013 John W. Eaton

This file is part of Octave.

Octave is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3 of the License, or (at your
option) any later version.

Octave is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License
along with Octave; see the file COPYING.  If not, see
<http://www.gnu.org/licenses/>.

*/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <limits>

#include "str-vec.h"
#include "quit.h"

#include "defun.h"
#include "error.h"
#include "ov.h"
#include "ov-uint64.h"
#include "ov-uint32.h"
#include "ov-uint16.h"
#include "ov-uint8.h"
#include "ov-int64.h"
#include "ov-int32.h"
#include "ov-int16.h"
#include "ov-int8.h"
#include "ov-float.h"
#include "ov-scalar.h"
#include "ov-re-mat.h"
#include "ov-bool.h"

#include <functional>

#if !defined (HAVE_CXX_BITWISE_OP_TEMPLATES)
namespace std
{
  template <typename T>
  struct bit_and
  {
  public:
    T operator() (const T & op1, const T & op2) const { return (op1 & op2); }
  };

  template <typename T>
  struct bit_or
  {
  public:
    T operator() (const T & op1, const T & op2) const { return (op1 | op2); }
  };

  template <typename T>
  struct bit_xor
  {
  public:
    T operator() (const T & op1, const T & op2) const { return (op1 ^ op2); }
  };
}
#endif

template <typename OP, typename T>
octave_value
bitopxx (const OP& op, const std::string& fname,
         const Array<T>& x, const Array<T>& y)
{
  int nelx = x.numel ();
  int nely = y.numel ();

  bool is_scalar_op = (nelx == 1 || nely == 1);

  dim_vector dvx = x.dims ();
  dim_vector dvy = y.dims ();

  bool is_array_op = (dvx == dvy);

  octave_value retval;
  if (is_array_op || is_scalar_op)
    {
      Array<T> result;

      if (nelx != 1)
        result.resize (dvx);
      else
        result.resize (dvy);

      for (int i = 0; i < nelx; i++)
        if (is_scalar_op)
          for (int k = 0; k < nely; k++)
            result(i+k) = op (x(i), y(k));
        else
          result(i) = op (x(i), y(i));

      retval = result;
    }
  else
    error ("%s: size of X and Y must match, or one operand must be a scalar",
           fname.c_str ());

  return retval;
}

// Trampoline function, instantiates the proper template above, with
// reflective information hardwired. We can't hardwire this information
// in Fbitxxx DEFUNs below, because at that moment, we still don't have
// information about which integer types we need to instantiate.
template<typename T>
octave_value
bitopx (const std::string& fname, const Array<T>& x, const Array<T>& y)
{
  if (fname == "bitand")
    return bitopxx (std::bit_and<T>(), fname, x, y);
  if (fname == "bitor")
    return bitopxx (std::bit_or<T>(), fname, x, y);

  //else (fname == "bitxor")
  return bitopxx (std::bit_xor<T>(), fname, x, y);
}

octave_value
bitop (const std::string& fname, const octave_value_list& args)
{
  octave_value retval;

  int nargin = args.length ();

  if (nargin == 2)
    {
      if ((args(0).class_name () == octave_scalar::static_class_name ())
          || (args(0).class_name () == octave_float_scalar::static_class_name ())
          || (args(0).class_name () == octave_bool::static_class_name ())
          || (args(1).class_name () == octave_scalar::static_class_name ())
          || (args(1).class_name () == octave_float_scalar::static_class_name ())
          || (args(1).class_name () == octave_bool::static_class_name ()))
        {
          bool arg0_is_int = (args(0).class_name () !=
                              octave_scalar::static_class_name () &&
                              args(0).class_name () !=
                              octave_float_scalar::static_class_name () &&
                              args(0).class_name () !=
                              octave_bool::static_class_name ());
          bool arg1_is_int = (args(1).class_name () !=
                              octave_scalar::static_class_name () &&
                              args(1).class_name () !=
                              octave_float_scalar::static_class_name () &&
                              args(1).class_name () !=
                              octave_bool::static_class_name ());
          bool arg0_is_float = args(0).class_name () ==
                               octave_float_scalar::static_class_name ();
          bool arg1_is_float = args(1).class_name () ==
                               octave_float_scalar::static_class_name ();

          if (! (arg0_is_int || arg1_is_int))
            {
              if (! (arg0_is_float || arg1_is_float))
                {
                  uint64NDArray x (args(0).array_value ());
                  uint64NDArray y (args(1).array_value ());
                  if (! error_state)
                    retval = bitopx (fname, x, y).array_value ();
                }
              else if (arg0_is_float && arg1_is_float)
                {
                  uint64NDArray x (args(0).float_array_value ());
                  uint64NDArray y (args(1).float_array_value ());
                  if (! error_state)
                    retval = bitopx (fname, x, y).float_array_value ();
                }
              else
                {
                  int p = (arg0_is_float ? 1 : 0);
                  int q = (arg0_is_float ? 0 : 1);

                  uint64NDArray x (args(p).array_value ());
                  uint64NDArray y (args(q).float_array_value ());
                  if (! error_state)
                    retval = bitopx (fname, x, y).float_array_value ();
                }
            }
          else
            {
              int p = (arg0_is_int ? 1 : 0);
              int q = (arg0_is_int ? 0 : 1);

              NDArray dx = args(p).array_value ();

              if (args(q).type_id () == octave_uint64_matrix::static_type_id ()
                  || args(q).type_id () == octave_uint64_scalar::static_type_id ())
                {
                  uint64NDArray x (dx);
                  uint64NDArray y = args(q).uint64_array_value ();
                  if (! error_state)
                    retval = bitopx (fname, x, y);
                }
              else if (args(q).type_id () == octave_uint32_matrix::static_type_id ()
                       || args(q).type_id () == octave_uint32_scalar::static_type_id ())
                {
                  uint32NDArray x (dx);
                  uint32NDArray y = args(q).uint32_array_value ();
                  if (! error_state)
                    retval = bitopx (fname, x, y);
                }
              else if (args(q).type_id () == octave_uint16_matrix::static_type_id ()
                       || args(q).type_id () == octave_uint16_scalar::static_type_id ())
                {
                  uint16NDArray x (dx);
                  uint16NDArray y = args(q).uint16_array_value ();
                  if (! error_state)
                    retval = bitopx (fname, x, y);
                }
              else if (args(q).type_id () == octave_uint8_matrix::static_type_id ()
                       || args(q).type_id () == octave_uint8_scalar::static_type_id ())
                {
                  uint8NDArray x (dx);
                  uint8NDArray y = args(q).uint8_array_value ();
                  if (! error_state)
                    retval = bitopx (fname, x, y);
                }
              else if (args(q).type_id () == octave_int64_matrix::static_type_id ()
                       || args(q).type_id () == octave_int64_scalar::static_type_id ())
                {
                  int64NDArray x (dx);
                  int64NDArray y = args(q).int64_array_value ();
                  if (! error_state)
                    retval = bitopx (fname, x, y);
                }
              else if (args(q).type_id () == octave_int32_matrix::static_type_id ()
                       || args(q).type_id () == octave_int32_scalar::static_type_id ())
                {
                  int32NDArray x (dx);
                  int32NDArray y = args(q).int32_array_value ();
                  if (! error_state)
                    retval = bitopx (fname, x, y);
                }
              else if (args(q).type_id () == octave_int16_matrix::static_type_id ()
                       || args(q).type_id () == octave_int16_scalar::static_type_id ())
                {
                  int16NDArray x (dx);
                  int16NDArray y = args(q).int16_array_value ();
                  if (! error_state)
                    retval  = bitopx (fname, x, y);
                }
              else if (args(q).type_id () == octave_int8_matrix::static_type_id ()
                       || args(q).type_id () == octave_int8_scalar::static_type_id ())
                {
                  int8NDArray x (dx);
                  int8NDArray y = args(q).int8_array_value ();
                  if (! error_state)
                    retval = bitopx (fname, x, y);
                }
              else
                error ("%s: invalid operand type", fname.c_str ());
            }
        }
      else if (args(0).class_name () == args(1).class_name ())
        {
          if (args(0).type_id () == octave_uint64_matrix::static_type_id ()
              || args(0).type_id () == octave_uint64_scalar::static_type_id ())
            {
              uint64NDArray x = args(0).uint64_array_value ();
              uint64NDArray y = args(1).uint64_array_value ();
              if (! error_state)
                retval = bitopx (fname, x, y);
            }
          else if (args(0).type_id () == octave_uint32_matrix::static_type_id ()
                   || args(0).type_id () == octave_uint32_scalar::static_type_id ())
            {
              uint32NDArray x = args(0).uint32_array_value ();
              uint32NDArray y = args(1).uint32_array_value ();
              if (! error_state)
                retval = bitopx (fname, x, y);
            }
          else if (args(0).type_id () == octave_uint16_matrix::static_type_id ()
                   || args(0).type_id () == octave_uint16_scalar::static_type_id ())
            {
              uint16NDArray x = args(0).uint16_array_value ();
              uint16NDArray y = args(1).uint16_array_value ();
              if (! error_state)
                retval = bitopx (fname, x, y);
            }
          else if (args(0).type_id () == octave_uint8_matrix::static_type_id ()
                   || args(0).type_id () == octave_uint8_scalar::static_type_id ())
            {
              uint8NDArray x = args(0).uint8_array_value ();
              uint8NDArray y = args(1).uint8_array_value ();
              if (! error_state)
                retval = bitopx (fname, x, y);
            }
          else if (args(0).type_id () == octave_int64_matrix::static_type_id ()
                   || args(0).type_id () == octave_int64_scalar::static_type_id ())
            {
              int64NDArray x = args(0).int64_array_value ();
              int64NDArray y = args(1).int64_array_value ();
              if (! error_state)
                retval = bitopx (fname, x, y);
            }
          else if (args(0).type_id () == octave_int32_matrix::static_type_id ()
                   || args(0).type_id () == octave_int32_scalar::static_type_id ())
            {
              int32NDArray x = args(0).int32_array_value ();
              int32NDArray y = args(1).int32_array_value ();
              if (! error_state)
                retval = bitopx (fname, x, y);
            }
          else if (args(0).type_id () == octave_int16_matrix::static_type_id ()
                   || args(0).type_id () == octave_int16_scalar::static_type_id ())
            {
              int16NDArray x = args(0).int16_array_value ();
              int16NDArray y = args(1).int16_array_value ();
              if (! error_state)
                retval = bitopx (fname, x, y);
            }
          else if (args(0).type_id () == octave_int8_matrix::static_type_id ()
                   || args(0).type_id () == octave_int8_scalar::static_type_id ())
            {
              int8NDArray x = args(0).int8_array_value ();
              int8NDArray y = args(1).int8_array_value ();
              if (! error_state)
                retval = bitopx (fname, x, y);
            }
          else
            error ("%s: invalid operand type", fname.c_str ());
        }
      else
        error ("%s: must have matching operand types", fname.c_str ());
    }
  else
    print_usage ();

  return retval;
}

DEFUN (bitand, args, ,
       "-*- texinfo -*-\n\
@deftypefn {Built-in Function} {} bitand (@var{x}, @var{y})\n\
Return the bitwise AND of non-negative integers.\n\
@var{x}, @var{y} must be in the range [0,bitmax]\n\
@seealso{bitor, bitxor, bitset, bitget, bitcmp, bitshift, bitmax}\n\
@end deftypefn")
{
  return bitop ("bitand", args);
}

DEFUN (bitor, args, ,
       "-*- texinfo -*-\n\
@deftypefn {Built-in Function} {} bitor (@var{x}, @var{y})\n\
Return the bitwise OR of non-negative integers.\n\
@var{x}, @var{y} must be in the range [0,bitmax]\n\
@seealso{bitor, bitxor, bitset, bitget, bitcmp, bitshift, bitmax}\n\
@end deftypefn")
{
  return bitop ("bitor", args);
}

DEFUN (bitxor, args, ,
       "-*- texinfo -*-\n\
@deftypefn {Built-in Function} {} bitxor (@var{x}, @var{y})\n\
Return the bitwise XOR of non-negative integers.\n\
@var{x}, @var{y} must be in the range [0,bitmax]\n\
@seealso{bitand, bitor, bitset, bitget, bitcmp, bitshift, bitmax}\n\
@end deftypefn")
{
  return bitop ("bitxor", args);
}

template <typename T>
static int64_t
max_mantissa_value ()
{
  return (static_cast<int64_t> (1) << std::numeric_limits<T>::digits) - 1;
}

static int64_t
bitshift (double a, int n, int64_t mask)
{
  // In the name of bug-for-bug compatibility.
  if (a < 0)
    return -bitshift (-a, n, mask);

  if (n > 0)
    return (static_cast<int64_t> (a) << n) & mask;
  else if (n < 0)
    return (static_cast<int64_t> (a) >> -n) & mask;
  else
    return static_cast<int64_t> (a) & mask;
}

static int64_t
bitshift (float a, int n, int64_t mask)
{
  // In the name of bug-for-bug compatibility.
  if (a < 0)
    return -bitshift (-a, n, mask);

  if (n > 0)
    return (static_cast<int64_t> (a) << n) & mask;
  else if (n < 0)
    return (static_cast<int64_t> (a) >> -n) & mask;
  else
    return static_cast<int64_t> (a) & mask;
}

// Note that the bitshift operators are undefined if shifted by more
// bits than in the type, so we need to test for the size of the
// shift.

#define DO_BITSHIFT(T) \
  if (! error_state) \
    { \
      double d1, d2; \
 \
      if (n.all_integers (d1, d2)) \
        { \
          int m_nel = m.numel (); \
          int n_nel = n.numel (); \
 \
          bool is_scalar_op = (m_nel == 1 || n_nel == 1); \
 \
          dim_vector m_dv = m.dims (); \
          dim_vector n_dv = n.dims (); \
 \
          bool is_array_op = (m_dv == n_dv); \
 \
          if (is_array_op || is_scalar_op) \
            { \
              T ## NDArray result; \
 \
              if (m_nel != 1) \
                result.resize (m_dv); \
              else \
                result.resize (n_dv); \
 \
              for (int i = 0; i < m_nel; i++) \
                if (is_scalar_op) \
                  for (int k = 0; k < n_nel; k++) \
                    if (static_cast<int> (n(k)) >= bits_in_type) \
                      result(i+k) = 0; \
                    else \
                      result(i+k) = bitshift (m(i), static_cast<int> (n(k)), mask); \
                else \
                  if (static_cast<int> (n(i)) >= bits_in_type) \
                    result(i) = 0;                                      \
                  else                                          \
                    result(i) = bitshift (m(i), static_cast<int> (n(i)), mask); \
 \
              retval = result; \
            } \
          else \
            error ("bitshift: size of A and N must match, or one operand must be a scalar"); \
        } \
      else \
        error ("bitshift: expecting integer as second argument"); \
    }

#define DO_UBITSHIFT(T, N) \
  do \
    { \
      int bits_in_type = octave_ ## T :: nbits (); \
      T ## NDArray m = m_arg.T ## _array_value (); \
        octave_ ## T mask = octave_ ## T::max (); \
      if ((N) < bits_in_type) \
        mask = bitshift (mask, (N) - bits_in_type); \
      else if ((N) < 1) \
        mask = 0; \
      DO_BITSHIFT (T); \
    } \
  while (0)

#define DO_SBITSHIFT(T, N) \
  do \
    { \
      int bits_in_type = octave_ ## T :: nbits (); \
      T ## NDArray m = m_arg.T ## _array_value (); \
        octave_ ## T mask = octave_ ## T::max (); \
      if ((N) < bits_in_type) \
        mask = bitshift (mask, (N) - bits_in_type); \
      else if ((N) < 1) \
        mask = 0; \
      mask = mask | octave_ ## T :: min (); /* FIXME: 2's complement only? */ \
      DO_BITSHIFT (T); \
    } \
  while (0)

DEFUN (bitshift, args, ,
       "-*- texinfo -*-\n\
@deftypefn  {Built-in Function} {} bitshift (@var{a}, @var{k})\n\
@deftypefnx {Built-in Function} {} bitshift (@var{a}, @var{k}, @var{n})\n\
Return a @var{k} bit shift of @var{n}-digit unsigned\n\
integers in @var{a}.  A positive @var{k} leads to a left shift;\n\
A negative value to a right shift.  If @var{n} is omitted it defaults\n\
to log2(bitmax)+1.\n\
@var{n} must be in the range [1,log2(bitmax)+1] usually [1,33].\n\
\n\
@example\n\
@group\n\
bitshift (eye (3), 1)\n\
@result{}\n\
@group\n\
2 0 0\n\
0 2 0\n\
0 0 2\n\
@end group\n\
\n\
bitshift (10, [-2, -1, 0, 1, 2])\n\
@result{} 2   5  10  20  40\n\
@c FIXME: restore this example when third arg is allowed to be an array.\n\
@c\n\
@c\n\
@c bitshift ([1, 10], 2, [3,4])\n\
@c @result{} 4  8\n\
@end group\n\
@end example\n\
@seealso{bitand, bitor, bitxor, bitset, bitget, bitcmp, bitmax}\n\
@end deftypefn")
{
  octave_value retval;

  int nargin = args.length ();

  if (nargin == 2 || nargin == 3)
    {
      int nbits = 64;

      NDArray n = args(1).array_value ();

      if (error_state)
        error ("bitshift: expecting integer as second argument");
      else
        {
          if (nargin == 3)
            {
              // FIXME: for compatibility, we should accept an array
              // or a scalar as the third argument.
              if (args(2).numel () > 1)
                error ("bitshift: N must be a scalar integer");
              else
                {
                  nbits = args(2).int_value ();

                  if (error_state)
                    error ("bitshift: N must be an integer");
                  else if (nbits < 0)
                    error ("bitshift: N must be positive");
                }
            }
        }

      if (error_state)
        return retval;

      octave_value m_arg = args(0);
      std::string cname = m_arg.class_name ();

      if (cname == "uint8")
        DO_UBITSHIFT (uint8, nbits < 8 ? nbits : 8);
      else if (cname == "uint16")
        DO_UBITSHIFT (uint16, nbits < 16 ? nbits : 16);
      else if (cname == "uint32")
        DO_UBITSHIFT (uint32, nbits < 32 ? nbits : 32);
      else if (cname == "uint64")
        DO_UBITSHIFT (uint64, nbits < 64 ? nbits : 64);
      else if (cname == "int8")
        DO_SBITSHIFT (int8, nbits < 8 ? nbits : 8);
      else if (cname == "int16")
        DO_SBITSHIFT (int16, nbits < 16 ? nbits : 16);
      else if (cname == "int32")
        DO_SBITSHIFT (int32, nbits < 32 ? nbits : 32);
      else if (cname == "int64")
        DO_SBITSHIFT (int64, nbits < 64 ? nbits : 64);
      else if (cname == "double")
        {
          static const int bits_in_mantissa
            = std::numeric_limits<double>::digits;

          nbits = (nbits < bits_in_mantissa ? nbits : bits_in_mantissa);
          int64_t mask = max_mantissa_value<double> ();
          if (nbits < bits_in_mantissa)
            mask = mask >> (bits_in_mantissa - nbits);
          else if (nbits < 1)
            mask = 0;
          int bits_in_type = sizeof (double)
                             * std::numeric_limits<unsigned char>::digits;
          NDArray m = m_arg.array_value ();
          DO_BITSHIFT ();
        }
      else if (cname == "single")
        {
          static const int bits_in_mantissa
            = std::numeric_limits<float>::digits;
          nbits = (nbits < bits_in_mantissa ? nbits : bits_in_mantissa);
          int64_t mask = max_mantissa_value<float> ();
          if (nbits < bits_in_mantissa)
            mask = mask >> (bits_in_mantissa - nbits);
          else if (nbits < 1)
            mask = 0;
          int bits_in_type = sizeof (float)
                             * std::numeric_limits<unsigned char>::digits;
          FloatNDArray m = m_arg.float_array_value ();
          DO_BITSHIFT (Float);
        }
      else
        error ("bitshift: not defined for %s objects", cname.c_str ());
    }
  else
    print_usage ();

  return retval;
}

DEFUN (bitmax, args, ,
       "-*- texinfo -*-\n\
@deftypefn  {Built-in Function} {} bitmax ()\n\
@deftypefnx {Built-in Function} {} bitmax (\"double\")\n\
@deftypefnx {Built-in Function} {} bitmax (\"single\")\n\
Return the largest integer that can be represented within a floating point\n\
value.  The default class is @qcode{\"double\"}, but @qcode{\"single\"} is a\n\
valid option.  On IEEE-754 compatible systems, @code{bitmax} is\n\
@w{@math{2^{53} - 1}} for @qcode{\"double\"} and @w{@math{2^{24} -1}} for\n\
@qcode{\"single\"}.\n\
@seealso{flintmax, intmax, realmax, realmin}\n\
@end deftypefn")
{
  octave_value retval;
  std::string cname = "double";
  int nargin = args.length ();

  if (nargin == 1 && args(0).is_string ())
    cname = args(0).string_value ();
  else if (nargin != 0)
    {
      print_usage ();
      return retval;
    }

  if (cname == "double")
    retval = (static_cast<double> (max_mantissa_value<double> ()));
  else if (cname == "single")
    retval = (static_cast<float> (max_mantissa_value<float> ()));
  else
    error ("bitmax: not defined for class '%s'", cname.c_str ());

  return retval;
}

DEFUN (flintmax, args, ,
       "-*- texinfo -*-\n\
@deftypefn  {Built-in Function} {} flintmax ()\n\
@deftypefnx {Built-in Function} {} flintmax (\"double\")\n\
@deftypefnx {Built-in Function} {} flintmax (\"single\")\n\
Return the largest integer that can be represented consecutively in a\n\
floating point value.  The default class is @qcode{\"double\"}, but\n\
@qcode{\"single\"} is a valid option.  On IEEE-754 compatible systems,\n\
@code{flintmax} is @w{@math{2^53}} for @qcode{\"double\"} and\n\
@w{@math{2^24}} for @qcode{\"single\"}.\n\
@seealso{bitmax, intmax, realmax, realmin}\n\
@end deftypefn")
{
  octave_value retval;
  std::string cname = "double";
  int nargin = args.length ();

  if (nargin == 1 && args(0).is_string ())
    cname = args(0).string_value ();
  else if (nargin != 0)
    {
      print_usage ();
      return retval;
    }

  if (cname == "double")
    retval = (static_cast<double> (max_mantissa_value<double> () + 1));
  else if (cname == "single")
    retval = (static_cast<float> (max_mantissa_value<float> () + 1));
  else
    error ("flintmax: not defined for class '%s'", cname.c_str ());

  return retval;
}

DEFUN (intmax, args, ,
       "-*- texinfo -*-\n\
@deftypefn {Built-in Function} {} intmax (@var{type})\n\
Return the largest integer that can be represented in an integer type.\n\
The variable @var{type} can be\n\
\n\
@table @code\n\
@item int8\n\
signed 8-bit integer.\n\
\n\
@item int16\n\
signed 16-bit integer.\n\
\n\
@item int32\n\
signed 32-bit integer.\n\
\n\
@item int64\n\
signed 64-bit integer.\n\
\n\
@item uint8\n\
unsigned 8-bit integer.\n\
\n\
@item uint16\n\
unsigned 16-bit integer.\n\
\n\
@item uint32\n\
unsigned 32-bit integer.\n\
\n\
@item uint64\n\
unsigned 64-bit integer.\n\
@end table\n\
\n\
The default for @var{type} is @code{int32}.\n\
@seealso{intmin, flintmax, bitmax}\n\
@end deftypefn")
{
  octave_value retval;
  std::string cname = "int32";
  int nargin = args.length ();

  if (nargin == 1 && args(0).is_string ())
    cname = args(0).string_value ();
  else if (nargin != 0)
    {
      print_usage ();
      return retval;
    }

  if (cname == "uint8")
    retval = octave_uint8 (std::numeric_limits<uint8_t>::max ());
  else if (cname == "uint16")
    retval = octave_uint16 (std::numeric_limits<uint16_t>::max ());
  else if (cname == "uint32")
    retval = octave_uint32 (std::numeric_limits<uint32_t>::max ());
  else if (cname == "uint64")
    retval = octave_uint64 (std::numeric_limits<uint64_t>::max ());
  else if (cname == "int8")
    retval = octave_int8 (std::numeric_limits<int8_t>::max ());
  else if (cname == "int16")
    retval = octave_int16 (std::numeric_limits<int16_t>::max ());
  else if (cname == "int32")
    retval = octave_int32 (std::numeric_limits<int32_t>::max ());
  else if (cname == "int64")
    retval = octave_int64 (std::numeric_limits<int64_t>::max ());
  else
    error ("intmax: not defined for '%s' objects", cname.c_str ());

  return retval;
}

DEFUN (intmin, args, ,
       "-*- texinfo -*-\n\
@deftypefn {Built-in Function} {} intmin (@var{type})\n\
Return the smallest integer that can be represented in an integer type.\n\
The variable @var{type} can be\n\
\n\
@table @code\n\
@item int8\n\
signed 8-bit integer.\n\
\n\
@item int16\n\
signed 16-bit integer.\n\
\n\
@item int32\n\
signed 32-bit integer.\n\
\n\
@item int64\n\
signed 64-bit integer.\n\
\n\
@item uint8\n\
unsigned 8-bit integer.\n\
\n\
@item uint16\n\
unsigned 16-bit integer.\n\
\n\
@item uint32\n\
unsigned 32-bit integer.\n\
\n\
@item uint64\n\
unsigned 64-bit integer.\n\
@end table\n\
\n\
The default for @var{type} is @code{int32}.\n\
@seealso{intmax, flintmax, bitmax}\n\
@end deftypefn")
{
  octave_value retval;
  std::string cname = "int32";
  int nargin = args.length ();

  if (nargin == 1 && args(0).is_string ())
    cname = args(0).string_value ();
  else if (nargin != 0)
    {
      print_usage ();
      return retval;
    }

  if (cname == "uint8")
    retval = octave_uint8 (std::numeric_limits<uint8_t>::min ());
  else if (cname == "uint16")
    retval = octave_uint16 (std::numeric_limits<uint16_t>::min ());
  else if (cname == "uint32")
    retval = octave_uint32 (std::numeric_limits<uint32_t>::min ());
  else if (cname == "uint64")
    retval = octave_uint64 (std::numeric_limits<uint64_t>::min ());
  else if (cname == "int8")
    retval = octave_int8 (std::numeric_limits<int8_t>::min ());
  else if (cname == "int16")
    retval = octave_int16 (std::numeric_limits<int16_t>::min ());
  else if (cname == "int32")
    retval = octave_int32 (std::numeric_limits<int32_t>::min ());
  else if (cname == "int64")
    retval = octave_int64 (std::numeric_limits<int64_t>::min ());
  else
    error ("intmin: not defined for '%s' objects", cname.c_str ());

  return retval;
}

DEFUN (sizemax, args, ,
       "-*- texinfo -*-\n\
@deftypefn {Built-in Function} {} sizemax ()\n\
Return the largest value allowed for the size of an array.\n\
If Octave is compiled with 64-bit indexing, the result is of class int64,\n\
otherwise it is of class int32.  The maximum array size is slightly\n\
smaller than the maximum value allowable for the relevant class as reported\n\
by @code{intmax}.\n\
@seealso{intmax}\n\
@end deftypefn")
{
  octave_value retval;

  if (args.length () == 0)
    retval = octave_int<octave_idx_type> (dim_vector::dim_max ());
  else
    print_usage ();

  return retval;
}