view liboctave/util/oct-inttypes.h @ 31605:e88a07dec498 stable

maint: Use macros to begin/end C++ namespaces. * oct-conf-post-public.in.h: Define two macros (OCTAVE_BEGIN_NAMESPACE, OCTAVE_END_NAMESPACE) that can be used to start/end a namespace. * mk-opts.pl, build-env.h, build-env.in.cc, __betainc__.cc, __contourc__.cc, __dsearchn__.cc, __eigs__.cc, __expint__.cc, __ftp__.cc, __gammainc__.cc, __ichol__.cc, __ilu__.cc, __isprimelarge__.cc, __lin_interpn__.cc, __magick_read__.cc, __pchip_deriv__.cc, __qp__.cc, amd.cc, auto-shlib.cc, auto-shlib.h, balance.cc, base-text-renderer.cc, base-text-renderer.h, besselj.cc, bitfcns.cc, bsxfun.cc, c-file-ptr-stream.cc, c-file-ptr-stream.h, call-stack.cc, call-stack.h, ccolamd.cc, cellfun.cc, chol.cc, colamd.cc, colloc.cc, conv2.cc, daspk.cc, dasrt.cc, dassl.cc, data.cc, data.h, debug.cc, defaults.cc, defaults.h, defun-int.h, defun.cc, det.cc, dirfns.cc, display.cc, display.h, dlmread.cc, dmperm.cc, dot.cc, dynamic-ld.cc, dynamic-ld.h, eig.cc, ellipj.cc, environment.cc, environment.h, error.cc, error.h, errwarn.h, event-manager.cc, event-manager.h, event-queue.cc, event-queue.h, fcn-info.cc, fcn-info.h, fft.cc, fft2.cc, fftn.cc, file-io.cc, filter.cc, find.cc, ft-text-renderer.cc, ft-text-renderer.h, gcd.cc, getgrent.cc, getpwent.cc, getrusage.cc, givens.cc, gl-render.cc, gl-render.h, gl2ps-print.cc, gl2ps-print.h, graphics-toolkit.cc, graphics-toolkit.h, graphics.cc, graphics.in.h, gsvd.cc, gtk-manager.cc, gtk-manager.h, hash.cc, help.cc, help.h, hess.cc, hex2num.cc, hook-fcn.cc, hook-fcn.h, input.cc, input.h, interpreter-private.cc, interpreter-private.h, interpreter.cc, interpreter.h, inv.cc, jsondecode.cc, jsonencode.cc, kron.cc, latex-text-renderer.cc, latex-text-renderer.h, load-path.cc, load-path.h, load-save.cc, load-save.h, lookup.cc, ls-ascii-helper.cc, ls-ascii-helper.h, ls-oct-text.cc, ls-utils.cc, ls-utils.h, lsode.cc, lu.cc, mappers.cc, matrix_type.cc, max.cc, mex-private.h, mex.cc, mgorth.cc, nproc.cc, oct-fstrm.cc, oct-fstrm.h, oct-hdf5-types.cc, oct-hdf5-types.h, oct-hist.cc, oct-hist.h, oct-iostrm.cc, oct-iostrm.h, oct-opengl.h, oct-prcstrm.cc, oct-prcstrm.h, oct-procbuf.cc, oct-procbuf.h, oct-process.cc, oct-process.h, oct-stdstrm.h, oct-stream.cc, oct-stream.h, oct-strstrm.cc, oct-strstrm.h, oct-tex-lexer.in.ll, oct-tex-parser.yy, ordqz.cc, ordschur.cc, pager.cc, pager.h, pinv.cc, pow2.cc, pr-flt-fmt.cc, pr-output.cc, procstream.cc, procstream.h, psi.cc, qr.cc, quad.cc, quadcc.cc, qz.cc, rand.cc, rcond.cc, regexp.cc, schur.cc, settings.cc, settings.h, sighandlers.cc, sighandlers.h, sparse-xdiv.cc, sparse-xdiv.h, sparse-xpow.cc, sparse-xpow.h, sparse.cc, spparms.cc, sqrtm.cc, stack-frame.cc, stack-frame.h, stream-euler.cc, strfind.cc, strfns.cc, sub2ind.cc, svd.cc, sylvester.cc, symbfact.cc, syminfo.cc, syminfo.h, symrcm.cc, symrec.cc, symrec.h, symscope.cc, symscope.h, symtab.cc, symtab.h, syscalls.cc, sysdep.cc, sysdep.h, text-engine.cc, text-engine.h, text-renderer.cc, text-renderer.h, time.cc, toplev.cc, tril.cc, tsearch.cc, typecast.cc, url-handle-manager.cc, url-handle-manager.h, urlwrite.cc, utils.cc, utils.h, variables.cc, variables.h, xdiv.cc, xdiv.h, xnorm.cc, xnorm.h, xpow.cc, xpow.h, __delaunayn__.cc, __fltk_uigetfile__.cc, __glpk__.cc, __init_fltk__.cc, __init_gnuplot__.cc, __ode15__.cc, __voronoi__.cc, audiodevinfo.cc, audioread.cc, convhulln.cc, fftw.cc, gzip.cc, mk-build-env-features.sh, mk-builtins.pl, cdef-class.cc, cdef-class.h, cdef-fwd.h, cdef-manager.cc, cdef-manager.h, cdef-method.cc, cdef-method.h, cdef-object.cc, cdef-object.h, cdef-package.cc, cdef-package.h, cdef-property.cc, cdef-property.h, cdef-utils.cc, cdef-utils.h, ov-base.cc, ov-base.h, ov-bool-mat.cc, ov-builtin.h, ov-cell.cc, ov-class.cc, ov-class.h, ov-classdef.cc, ov-classdef.h, ov-complex.cc, ov-fcn-handle.cc, ov-fcn-handle.h, ov-fcn.h, ov-java.cc, ov-java.h, ov-mex-fcn.h, ov-null-mat.cc, ov-oncleanup.cc, ov-struct.cc, ov-typeinfo.cc, ov-typeinfo.h, ov-usr-fcn.cc, ov-usr-fcn.h, ov.cc, ov.h, octave.cc, octave.h, mk-ops.sh, op-b-b.cc, op-b-bm.cc, op-b-sbm.cc, op-bm-b.cc, op-bm-bm.cc, op-bm-sbm.cc, op-cdm-cdm.cc, op-cell.cc, op-chm.cc, op-class.cc, op-cm-cm.cc, op-cm-cs.cc, op-cm-m.cc, op-cm-s.cc, op-cm-scm.cc, op-cm-sm.cc, op-cs-cm.cc, op-cs-cs.cc, op-cs-m.cc, op-cs-s.cc, op-cs-scm.cc, op-cs-sm.cc, op-dm-dm.cc, op-dm-scm.cc, op-dm-sm.cc, op-dm-template.cc, op-dms-template.cc, op-fcdm-fcdm.cc, op-fcm-fcm.cc, op-fcm-fcs.cc, op-fcm-fm.cc, op-fcm-fs.cc, op-fcn.cc, op-fcs-fcm.cc, op-fcs-fcs.cc, op-fcs-fm.cc, op-fcs-fs.cc, op-fdm-fdm.cc, op-fm-fcm.cc, op-fm-fcs.cc, op-fm-fm.cc, op-fm-fs.cc, op-fs-fcm.cc, op-fs-fcs.cc, op-fs-fm.cc, op-fs-fs.cc, op-i16-i16.cc, op-i32-i32.cc, op-i64-i64.cc, op-i8-i8.cc, op-int-concat.cc, op-m-cm.cc, op-m-cs.cc, op-m-m.cc, op-m-s.cc, op-m-scm.cc, op-m-sm.cc, op-mi.cc, op-pm-pm.cc, op-pm-scm.cc, op-pm-sm.cc, op-pm-template.cc, op-range.cc, op-s-cm.cc, op-s-cs.cc, op-s-m.cc, op-s-s.cc, op-s-scm.cc, op-s-sm.cc, op-sbm-b.cc, op-sbm-bm.cc, op-sbm-sbm.cc, op-scm-cm.cc, op-scm-cs.cc, op-scm-m.cc, op-scm-s.cc, op-scm-scm.cc, op-scm-sm.cc, op-sm-cm.cc, op-sm-cs.cc, op-sm-m.cc, op-sm-s.cc, op-sm-scm.cc, op-sm-sm.cc, op-str-m.cc, op-str-s.cc, op-str-str.cc, op-struct.cc, op-ui16-ui16.cc, op-ui32-ui32.cc, op-ui64-ui64.cc, op-ui8-ui8.cc, ops.h, anon-fcn-validator.cc, anon-fcn-validator.h, bp-table.cc, bp-table.h, comment-list.cc, comment-list.h, filepos.h, lex.h, lex.ll, oct-lvalue.cc, oct-lvalue.h, oct-parse.yy, parse.h, profiler.cc, profiler.h, pt-anon-scopes.cc, pt-anon-scopes.h, pt-arg-list.cc, pt-arg-list.h, pt-args-block.cc, pt-args-block.h, pt-array-list.cc, pt-array-list.h, pt-assign.cc, pt-assign.h, pt-binop.cc, pt-binop.h, pt-bp.cc, pt-bp.h, pt-cbinop.cc, pt-cbinop.h, pt-cell.cc, pt-cell.h, pt-check.cc, pt-check.h, pt-classdef.cc, pt-classdef.h, pt-cmd.h, pt-colon.cc, pt-colon.h, pt-const.cc, pt-const.h, pt-decl.cc, pt-decl.h, pt-eval.cc, pt-eval.h, pt-except.cc, pt-except.h, pt-exp.cc, pt-exp.h, pt-fcn-handle.cc, pt-fcn-handle.h, pt-id.cc, pt-id.h, pt-idx.cc, pt-idx.h, pt-jump.h, pt-loop.cc, pt-loop.h, pt-mat.cc, pt-mat.h, pt-misc.cc, pt-misc.h, pt-pr-code.cc, pt-pr-code.h, pt-select.cc, pt-select.h, pt-spmd.cc, pt-spmd.h, pt-stmt.cc, pt-stmt.h, pt-tm-const.cc, pt-tm-const.h, pt-unop.cc, pt-unop.h, pt-vm-eval.cc, pt-walk.cc, pt-walk.h, pt.cc, pt.h, token.cc, token.h, Range.cc, Range.h, idx-vector.cc, idx-vector.h, range-fwd.h, CollocWt.cc, CollocWt.h, aepbalance.cc, aepbalance.h, chol.cc, chol.h, gepbalance.cc, gepbalance.h, gsvd.cc, gsvd.h, hess.cc, hess.h, lo-mappers.cc, lo-mappers.h, lo-specfun.cc, lo-specfun.h, lu.cc, lu.h, oct-convn.cc, oct-convn.h, oct-fftw.cc, oct-fftw.h, oct-norm.cc, oct-norm.h, oct-rand.cc, oct-rand.h, oct-spparms.cc, oct-spparms.h, qr.cc, qr.h, qrp.cc, qrp.h, randgamma.cc, randgamma.h, randmtzig.cc, randmtzig.h, randpoisson.cc, randpoisson.h, schur.cc, schur.h, sparse-chol.cc, sparse-chol.h, sparse-lu.cc, sparse-lu.h, sparse-qr.cc, sparse-qr.h, svd.cc, svd.h, child-list.cc, child-list.h, dir-ops.cc, dir-ops.h, file-ops.cc, file-ops.h, file-stat.cc, file-stat.h, lo-sysdep.cc, lo-sysdep.h, lo-sysinfo.cc, lo-sysinfo.h, mach-info.cc, mach-info.h, oct-env.cc, oct-env.h, oct-group.cc, oct-group.h, oct-password.cc, oct-password.h, oct-syscalls.cc, oct-syscalls.h, oct-time.cc, oct-time.h, oct-uname.cc, oct-uname.h, action-container.cc, action-container.h, base-list.h, cmd-edit.cc, cmd-edit.h, cmd-hist.cc, cmd-hist.h, f77-fcn.h, file-info.cc, file-info.h, lo-array-errwarn.cc, lo-array-errwarn.h, lo-hash.cc, lo-hash.h, lo-ieee.h, lo-regexp.cc, lo-regexp.h, lo-utils.cc, lo-utils.h, oct-base64.cc, oct-base64.h, oct-glob.cc, oct-glob.h, oct-inttypes.h, oct-mutex.cc, oct-mutex.h, oct-refcount.h, oct-shlib.cc, oct-shlib.h, oct-sparse.cc, oct-sparse.h, oct-string.h, octave-preserve-stream-state.h, pathsearch.cc, pathsearch.h, quit.cc, quit.h, unwind-prot.cc, unwind-prot.h, url-transfer.cc, url-transfer.h : Use new macros to begin/end C++ namespaces.
author Rik <rik@octave.org>
date Thu, 01 Dec 2022 14:23:45 -0800
parents e7fc6251b698
children aac27ad79be6
line wrap: on
line source

////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2004-2022 The Octave Project Developers
//
// See the file COPYRIGHT.md in the top-level directory of this
// distribution or <https://octave.org/copyright/>.
//
// 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
// <https://www.gnu.org/licenses/>.
//
////////////////////////////////////////////////////////////////////////

#if ! defined (octave_oct_inttypes_h)
#define octave_oct_inttypes_h 1

#include "octave-config.h"

#include <cmath>
#include <cstdlib>

#include <iosfwd>
#include <limits>

#include "lo-mappers.h"
#include "lo-traits.h"
#include "oct-inttypes-fwd.h"

#if defined (OCTAVE_INT_USE_LONG_DOUBLE)

OCTAVE_BEGIN_NAMESPACE(octave)

OCTAVE_BEGIN_NAMESPACE(math)

    inline long double round (long double x)
    {
      return std::roundl (x);
    }

    inline long double isnan (long double x)
    {
      return isnan (static_cast<double> (x));
    }

OCTAVE_END_NAMESPACE(math)
OCTAVE_END_NAMESPACE(octave)

#endif

// FIXME: we define this by our own because some compilers, such as
// MSVC, do not provide std::abs (int64_t) and std::abs (uint64_t).  In
// the future, it should go away in favor of std::abs.

template <typename T>
inline T
octave_int_abs (T x)
{
  return (x >= 0 ? x : -x);
}

// Query for an integer type of certain sizeof, and signedness.

template <int qsize, bool qsigned>
struct query_integer_type
{
public:

  static const bool registered = false;

  // Void shall result in a compile-time error if we attempt to use it
  // in computations.

  typedef void type;
};

#define OCTAVE_REGISTER_INT_TYPE(TYPE)                                  \
  template <>                                                           \
  class query_integer_type<sizeof (TYPE),                               \
                           std::numeric_limits<TYPE>::is_signed>        \
  {                                                                     \
  public:                                                               \
                                                                        \
    static const bool registered = true;                                \
                                                                        \
    typedef TYPE type;                                                  \
  }

// No two registered integers can share sizeof and signedness.
OCTAVE_REGISTER_INT_TYPE (int8_t);
OCTAVE_REGISTER_INT_TYPE (uint8_t);
OCTAVE_REGISTER_INT_TYPE (int16_t);
OCTAVE_REGISTER_INT_TYPE (uint16_t);
OCTAVE_REGISTER_INT_TYPE (int32_t);
OCTAVE_REGISTER_INT_TYPE (uint32_t);
OCTAVE_REGISTER_INT_TYPE (int64_t);
OCTAVE_REGISTER_INT_TYPE (uint64_t);

#undef OCTAVE_REGISTER_INT_TYPE

// Handles non-homogeneous integer comparisons.  Avoids doing useless
// tests.

class octave_int_cmp_op
{
  // This determines a suitable promotion type for T1 when meeting T2
  // in a binary relation.  If promotion to int or T2 is safe, it is
  // used.  Otherwise, the signedness of T1 is preserved and it is
  // widened if T2 is wider.  Notice that if this is applied to both
  // types, they must end up with equal size.

  template <typename T1, typename T2>
  class prom
  {
    // Promote to int?
    static const bool pint = (sizeof (T1) < sizeof (int)
                              && sizeof (T2) < sizeof (int));

    static const bool t1sig = std::numeric_limits<T1>::is_signed;
    static const bool t2sig = std::numeric_limits<T2>::is_signed;

    static const bool psig
      = (pint || (sizeof (T2) > sizeof (T1) && t2sig) || t1sig);

    static const int psize
      = (pint
         ? sizeof (int)
         : (sizeof (T2) > sizeof (T1) ? sizeof (T2) : sizeof (T1)));
  public:

    typedef typename query_integer_type<psize, psig>::type type;
  };

  // Implements comparisons between two types of equal size but
  // possibly different signedness.

  template <typename xop, int size>
  class uiop
  {
    typedef typename query_integer_type<size, false>::type utype;
    typedef typename query_integer_type<size, true>::type stype;

  public:

    static bool op (utype x, utype y)
    {
      return xop::op (x, y);
    }

    static bool op (stype x, stype y)
    {
      return xop::op (x, y);
    }

    static bool op (stype x, utype y)
    {
      return (x < 0) ? xop::ltval : xop::op (static_cast<utype> (x), y);
    }

    static bool op (utype x, stype y)
    {
      return (y < 0) ? xop::gtval : xop::op (x, static_cast<utype> (y));
    }
  };

public:

  // Rationale: Comparators have a single static method, rel(), that
  // returns the result of the binary relation.  They also have two
  // static boolean fields: ltval, gtval determine the value of x OP y
  // if x < y, x > y, respectively.

#define OCTAVE_REGISTER_INT_CMP_OP(NM, OP)              \
  class NM                                              \
  {                                                     \
  public:                                               \
                                                        \
    static const bool ltval = (0 OP 1);                 \
    static const bool gtval = (1 OP 0);                 \
                                                        \
    template <typename T>                               \
    static bool op (T x, T y) { return x OP y; }        \
  }

  OCTAVE_REGISTER_INT_CMP_OP (lt, <);
  OCTAVE_REGISTER_INT_CMP_OP (le, <=);
  OCTAVE_REGISTER_INT_CMP_OP (gt, >);
  OCTAVE_REGISTER_INT_CMP_OP (ge, >=);
  OCTAVE_REGISTER_INT_CMP_OP (eq, ==);
  OCTAVE_REGISTER_INT_CMP_OP (ne, !=);

#undef OCTAVE_REGISTER_INT_CMP_OP

  // We also provide two special relations: ct, yielding always true,
  // and cf, yielding always false.

#define OCTAVE_REGISTER_INT_CONST_OP(NM, VALUE) \
  class NM                                      \
  {                                             \
  public:                                       \
                                                \
    static const bool ltval = VALUE;            \
    static const bool gtval = VALUE;            \
                                                \
    template <typename T>                       \
      static bool op (T, T) { return VALUE; }   \
  }

  OCTAVE_REGISTER_INT_CONST_OP (ct, true);
  OCTAVE_REGISTER_INT_CONST_OP (cf, false);

#undef OCTAVE_REGISTER_INT_CONST_OP

  // Universal comparison operation.

  template <typename xop, typename T1, typename T2>
  static bool
  op (T1 x, T2 y)
  {
    typedef typename prom<T1, T2>::type PT1;
    typedef typename prom<T2, T1>::type PT2;

    return uiop<xop, sizeof (PT1)>::op (static_cast<PT1> (x),
                                        static_cast<PT2> (y));
  }

public:

  // Mixed comparisons.

  template <typename xop, typename T>
  static bool mop (T x, double y)
  {
    return xop::op (static_cast<double> (x), y);
  }

  template <typename xop, typename T>
  static bool mop (double x, T y)
  {
    return xop::op (x, static_cast<double> (y));
  }

#if defined (OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED)

#  define OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_CMP_OPS(T)    \
  template <typename xop>                                       \
  static OCTAVE_API bool external_mop (double, T);              \
                                                                \
  template <typename xop>                                       \
  static OCTAVE_API bool external_mop (T, double)

  OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_CMP_OPS (int64_t);
  OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_CMP_OPS (uint64_t);

#endif

  // Typecasting to doubles won't work properly for 64-bit integers --
  // they lose precision.  If we have long doubles, use them...

#if defined (OCTAVE_INT_USE_LONG_DOUBLE)

#  if defined (OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED)

#    define OCTAVE_DEFINE_LONG_DOUBLE_INT_CMP_OP(T)     \
  template <typename xop>                               \
  static bool mop (double x, T y)                       \
  {                                                     \
    return external_mop<xop> (x, y);                    \
  }                                                     \
                                                        \
  template <typename xop>                               \
  static bool mop (T x, double y)                       \
  {                                                     \
    return external_mop<xop> (x, y);                    \
  }

#  else

#    define OCTAVE_DEFINE_LONG_DOUBLE_INT_CMP_OP(T)     \
  template <typename xop>                               \
  static bool mop (double x, T y)                       \
  {                                                     \
    return xop::op (static_cast<long double> (x),       \
                    static_cast<long double> (y));      \
  }                                                     \
                                                        \
  template <typename xop>                               \
  static bool mop (T x, double y)                       \
  {                                                     \
    return xop::op (static_cast<long double> (x),       \
                    static_cast<long double> (y));      \
  }

#  endif

#else

  // ... otherwise, use external handlers

  // FIXME: We could declare directly the mop methods as external, but
  // we can't do this because bugs in gcc (<= 4.3) prevent explicit
  // instantiations later in that case.

#  define OCTAVE_DEFINE_LONG_DOUBLE_INT_CMP_OP(T)       \
  template <typename xop>                               \
  static OCTAVE_API bool emulate_mop (double, T);       \
                                                        \
  template <typename xop>                               \
  static bool mop (double x, T y)                       \
  {                                                     \
    return emulate_mop<xop> (x, y);                     \
  }                                                     \
                                                        \
  template <typename xop>                               \
  static OCTAVE_API bool emulate_mop (T, double);       \
                                                        \
  template <typename xop>                               \
  static bool mop (T x, double y)                       \
  {                                                     \
    return emulate_mop<xop> (x, y);                     \
  }

#endif

  OCTAVE_DEFINE_LONG_DOUBLE_INT_CMP_OP (int64_t)
  OCTAVE_DEFINE_LONG_DOUBLE_INT_CMP_OP (uint64_t)

#undef OCTAVE_DEFINE_LONG_DOUBLE_INT_CMP_OP
};

// Base integer class.  No data, just conversion methods and exception
// flags.

template <typename T>
class octave_int_base
{
public:

  static T min_val (void) { return std::numeric_limits<T>::min (); }
  static T max_val (void) { return std::numeric_limits<T>::max (); }

  // Convert integer value.

  template <typename S>
  static T truncate_int (const S& value)
  {
    // An exhaustive test whether the max and/or min check can be
    // omitted.

    static const bool t_is_signed = std::numeric_limits<T>::is_signed;
    static const bool s_is_signed = std::numeric_limits<S>::is_signed;

    static const int t_size = sizeof (T);
    static const int s_size = sizeof (S);

    static const bool omit_chk_min
      = (! s_is_signed || (t_is_signed && t_size >= s_size));

    static const bool omit_chk_max
      = (t_size > s_size
         || (t_size == s_size && (! t_is_signed || s_is_signed)));

    // If the check can be omitted, substitute constant false
    // relation.

    typedef octave_int_cmp_op::cf cf;
    typedef octave_int_cmp_op::lt lt;
    typedef octave_int_cmp_op::gt gt;
    typedef typename if_then_else<omit_chk_min, cf, lt>::result chk_min;
    typedef typename if_then_else<omit_chk_max, cf, gt>::result chk_max;

    // Efficiency of the following depends on inlining and dead code
    // elimination, but that should be a piece of cake for most
    // compilers.

    if (chk_min::op (value, static_cast<S> (min_val ())))
      return min_val ();
    else if (chk_max::op (value, static_cast<S> (max_val ())))
      return max_val ();
    else
      return static_cast<T> (value);
  }

private:

  // Compute a real-valued threshold for a max/min check.

  template <typename S>
  static S compute_threshold (S val, T orig_val)
  {
    // Fool optimizations (maybe redundant).

    val = octave::math::round (val);

    // If val is even, but orig_val is odd, we're one unit off.

    if (orig_val % 2 && val / 2 == octave::math::round (val / 2))
      // FIXME: is this always correct?
      val *= (static_cast<S> (1) - (std::numeric_limits<S>::epsilon () / 2));

    return val;
  }

public:

  // Convert a real number (check NaN and non-int).

  template <typename S>
  static OCTAVE_API T convert_real (const S& value);
};

// Saturated (homogeneous) integer arithmetics.  The signed and
// unsigned implementations are significantly different, so we
// implement another layer and completely specialize.  Arithmetics
// inherits from octave_int_base so that it can use its exceptions and
// truncation functions.

template <typename T, bool is_signed>
class octave_int_arith_base
{ };

// Unsigned arithmetics.  C++ standard requires it to be modular, so
// the overflows can be handled efficiently and reliably.

template <typename T>
class octave_int_arith_base<T, false> : octave_int_base<T>
{
public:

  static T abs (T x) { return x; }

  static T signum (T x) { return x ? static_cast<T> (1) : static_cast<T> (0); }

  // Shifts do not overflow.

  static T rshift (T x, int n) { return x >> n; }

  static T lshift (T x, int n) { return x << n; }

  static T minus (T) { return static_cast<T> (0); }

  // The overflow behavior for unsigned integers is guaranteed by
  // C and C++, so the following should always work.

  static T add (T x, T y)
  {
    T u = x + y;

    if (u < x)
      u = octave_int_base<T>::max_val ();

    return u;
  }

  static T sub (T x, T y)
  {
    T u = x - y;

    if (u > x)
      u = 0;

    return u;
  }

  // Multiplication is done using promotion to wider integer type.  If
  // there is no suitable promotion type, this operation *MUST* be
  // specialized.

  static T mul (T x, T y) { return mul_internal (x, y); }

  static T mul_internal (T x, T y)
  {
    // Promotion type for multiplication (if exists).

    typedef typename query_integer_type<2*sizeof (T), false>::type mptype;

    return octave_int_base<T>::truncate_int (static_cast<mptype> (x)
                                             * static_cast<mptype> (y));
  }

  // Division with rounding to nearest.  Note that / and % are
  // probably computed by a single instruction.

  static T div (T x, T y)
  {
    if (y != 0)
      {
        T z = x / y;
        T w = x % y;

        if (w >= y-w)
          z += 1;

        return z;
      }
    else
      return x ? octave_int_base<T>::max_val () : 0;
  }

  // Remainder.

  static T rem (T x, T y) { return y != 0 ? x % y : 0; }

  // Modulus.  Note the weird y = 0 case for Matlab compatibility.

  static T mod (T x, T y) { return y != 0 ? x % y : x; }
};

#if defined (OCTAVE_INT_USE_LONG_DOUBLE)

// Handle 64-bit multiply using long double.

#  if defined (OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED)

extern OCTAVE_API uint64_t
octave_external_uint64_uint64_mul (uint64_t, uint64_t);

#  endif

template <>
inline uint64_t
octave_int_arith_base<uint64_t, false>::mul_internal (uint64_t x, uint64_t y)
{
  uint64_t retval;

  long double p = static_cast<long double> (x) * static_cast<long double> (y);

  if (p > static_cast<long double> (octave_int_base<uint64_t>::max_val ()))
    retval = octave_int_base<uint64_t>::max_val ();
  else
    retval = static_cast<uint64_t> (p);

  return retval;
}

template <>
inline uint64_t
octave_int_arith_base<uint64_t, false>::mul (uint64_t x, uint64_t y)
{
#  if defined (OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED)
  return octave_external_uint64_uint64_mul (x, y);
#  else
  return mul_internal (x, y);
#  endif
}

#else

// Special handler for 64-bit integer multiply.

template <>
OCTAVE_API uint64_t
octave_int_arith_base<uint64_t, false>::mul_internal (uint64_t, uint64_t);

#endif

template <typename T>
class octave_int_arith_base<T, true> : octave_int_base<T>
{
  // The corresponding unsigned type.
  typedef typename query_integer_type<sizeof (T), false>::type UT;

public:

  // Returns 1 for negative number, 0 otherwise.

  static T __signbit (T x) { return (x < 0) ? 1 : 0; }

  static T abs (T x)
  {
    // -INT_MAX is safe because C++ actually allows only three
    // implementations of integers: sign & magnitude, ones complement
    // and twos complement.  The first test will, with modest
    // optimizations, evaluate at compile time, and maybe eliminate
    // the branch completely.

    return ((octave_int_base<T>::min_val () < -octave_int_base<T>::max_val ()
             && x == octave_int_base<T>::min_val ())
            ? octave_int_base<T>::max_val ()
            : ((x < 0) ? -x : x));
  }

  static T signum (T x)
  {
    // With modest optimizations, this will compile without a jump.

    return ((x > 0) ? 1 : 0) - __signbit (x);
  }

  // FIXME: we do not have an authority what signed shifts should
  // exactly do, so we define them the easy way.  Note that Matlab
  // does not define signed shifts.

  static T rshift (T x, int n) { return x >> n; }

  static T lshift (T x, int n) { return x << n; }

  // Minus has problems similar to abs.

  static T minus (T x)
  {
    return ((octave_int_base<T>::min_val () < -octave_int_base<T>::max_val ()
             && x == octave_int_base<T>::min_val ())
            ? octave_int_base<T>::max_val ()
            : -x);
  }

  static T add (T x, T y)
  {
    // Avoid anything that may overflow.

    return (y < 0
            ? (x < octave_int_base<T>::min_val () - y
               ? octave_int_base<T>::min_val ()
               : x + y)
            : (x > octave_int_base<T>::max_val () - y
               ? octave_int_base<T>::max_val ()
               : x + y));
  }

  static T sub (T x, T y)
  {
    // Avoid anything that may overflow.

    return (y < 0
            ? (x > octave_int_base<T>::max_val () + y
               ? octave_int_base<T>::max_val ()
               : x - y)
            : (x < octave_int_base<T>::min_val () + y
               ? octave_int_base<T>::min_val ()
               : x - y));
  }

  // Multiplication is done using promotion to wider integer type.  If
  // there is no suitable promotion type, this operation *MUST* be
  // specialized.

  static T mul (T x, T y) { return mul_internal (x, y); }

  static T mul_internal (T x, T y)
  {
    // Promotion type for multiplication (if exists).

    typedef typename query_integer_type<2*sizeof (T), true>::type mptype;

    return octave_int_base<T>::truncate_int (static_cast<mptype> (x)
           * static_cast<mptype> (y));
  }

  // Division.

  static T div (T x, T y)
  {
    T z;

    if (y == 0)
      {
        if (x < 0)
          z = octave_int_base<T>::min_val ();
        else if (x != 0)
          z = octave_int_base<T>::max_val ();
        else
          z = 0;
      }
    else if (y < 0)
      {
        // This is a special case that overflows as well.
        if (y == -1 && x == octave_int_base<T>::min_val ())
          z = octave_int_base<T>::max_val ();
        else
          {
            z = x / y;
            // Can't overflow, but std::abs (x) can!
            T w = -octave_int_abs (x % y);
            if (w <= y - w)
              z -= 1 - (__signbit (x) << 1);
          }
      }
    else
      {
        z = x / y;

        // FIXME: this is a workaround due to MSVC's absence of
        // std::abs (int64_t).  The call to octave_int_abs can't
        // overflow, but std::abs (x) can!
        T w = octave_int_abs (x % y);

        if (w >= y - w)
          z += 1 - (__signbit (x) << 1);
      }
    return z;
  }

  // Remainder.

  static T rem (T x, T y)
  {
    return y != 0 ? x % y : 0;
  }

  // Modulus.  Note the weird y = 0 case for Matlab compatibility.

  static T mod (T x, T y)
  {
    if (y != 0)
      {
        T r = x % y;
        return (r == 0) ? 0 : (((r < 0) != (y < 0)) ? r + y : r);
      }
    else
      return x;
  }
};

#if defined (OCTAVE_INT_USE_LONG_DOUBLE)

// Handle 64-bit multiply using long double

#  if defined (OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED)

extern OCTAVE_API int64_t
octave_external_int64_int64_mul (int64_t, int64_t);

#  endif

template <>
inline int64_t
octave_int_arith_base<int64_t, true>::mul_internal (int64_t x, int64_t y)
{
  int64_t retval;

  long double p = static_cast<long double> (x) * static_cast<long double> (y);

  if (p > static_cast<long double> (octave_int_base<int64_t>::max_val ()))
    retval = octave_int_base<int64_t>::max_val ();
  else if (p < static_cast<long double> (octave_int_base<int64_t>::min_val ()))
    retval = octave_int_base<int64_t>::min_val ();
  else
    retval = static_cast<int64_t> (p);

  return retval;
}

template <>
inline int64_t
octave_int_arith_base<int64_t, true>::mul (int64_t x, int64_t y)
{
#  if defined (OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED)
  return octave_external_int64_int64_mul (x, y);
#  else
  return mul_internal (x, y);
#  endif
}

#else

// Special handler for 64-bit integer multiply.

template <>
OCTAVE_API int64_t
octave_int_arith_base<int64_t, true>::mul_internal (int64_t, int64_t);

#endif

// This class simply selects the proper arithmetics.
template <typename T>
class octave_int_arith
  : public octave_int_arith_base<T, std::numeric_limits<T>::is_signed>
{ };

template <typename T>
class
OCTAVE_TEMPLATE_API
octave_int : public octave_int_base<T>
{
public:

  typedef T val_type;

  octave_int (void) : m_ival () { }

  octave_int (T i) : m_ival (i) { }

#if defined (OCTAVE_HAVE_OVERLOAD_CHAR_INT8_TYPES)

  // Always treat characters as unsigned.
  octave_int (char c)
    : m_ival (octave_int_base<T>::truncate_int (static_cast<unsigned char> (c)))
  { }

#endif

  octave_int (double d)
    : m_ival (octave_int_base<T>::convert_real (d)) { }

  octave_int (float d)
    : m_ival (octave_int_base<T>::convert_real (d)) { }

#if defined (OCTAVE_INT_USE_LONG_DOUBLE)

  octave_int (long double d)
    : m_ival (octave_int_base<T>::convert_real (d)) { }

#endif

  octave_int (bool b) : m_ival (b) { }

  template <typename U>
  octave_int (const U& i)
    : m_ival(octave_int_base<T>::truncate_int (i)) { }

  template <typename U>
  octave_int (const octave_int<U>& i)
    : m_ival (octave_int_base<T>::truncate_int (i.value ())) { }

  octave_int (const octave_int<T>&) = default;

  octave_int& operator = (const octave_int<T>&) = default;

  ~octave_int (void) = default;

  T value (void) const { return m_ival; }

  const unsigned char * iptr (void) const
  {
    return reinterpret_cast<const unsigned char *> (& m_ival);
  }

  bool operator ! (void) const { return ! m_ival; }

  bool bool_value (void) const { return static_cast<bool> (value ()); }

  char char_value (void) const { return static_cast<char> (value ()); }

  double double_value (void) const { return static_cast<double> (value ()); }

  float float_value (void) const { return static_cast<float> (value ()); }

  operator T (void) const { return value (); }

  octave_int<T> operator + () const { return *this; }

  // unary operators & mappers
#define OCTAVE_INT_UN_OP(OPNAME, NAME)          \
  inline octave_int<T>                          \
  OPNAME () const                               \
  {                                             \
    return octave_int_arith<T>::NAME (m_ival);  \
  }

  OCTAVE_INT_UN_OP (operator -, minus)
  OCTAVE_INT_UN_OP (abs, abs)
  OCTAVE_INT_UN_OP (signum, signum)

#undef OCTAVE_INT_UN_OP

  octave_int<T> operator ~ (void) const
  {
    T bitinv = ~ m_ival;
    return bitinv;
  }

  // Homogeneous binary integer operations.
#define OCTAVE_INT_BIN_OP(OP, NAME, ARGT)               \
  inline octave_int<T>                                  \
  operator OP (const ARGT& y) const                     \
  {                                                     \
    return octave_int_arith<T>::NAME (m_ival, y);       \
  }                                                     \
                                                        \
  inline octave_int<T>&                                 \
  operator OP##= (const ARGT& y)                        \
  {                                                     \
    m_ival = octave_int_arith<T>::NAME (m_ival, y);     \
    return *this;                                       \
  }

  OCTAVE_INT_BIN_OP (+, add, octave_int<T>)
  OCTAVE_INT_BIN_OP (-, sub, octave_int<T>)
  OCTAVE_INT_BIN_OP (*, mul, octave_int<T>)
  OCTAVE_INT_BIN_OP (/, div, octave_int<T>)
  OCTAVE_INT_BIN_OP (%, rem, octave_int<T>)
  OCTAVE_INT_BIN_OP (<<, lshift, int)
  OCTAVE_INT_BIN_OP (>>, rshift, int)

#undef OCTAVE_INT_BIN_OP

  static octave_int<T> min (void) { return std::numeric_limits<T>::min (); }
  static octave_int<T> max (void) { return std::numeric_limits<T>::max (); }

  static int nbits (void) { return std::numeric_limits<T>::digits; }

  static int byte_size (void) { return sizeof (T); }

  static const OCTAVE_API char * type_name ();

  // The following are provided for convenience.
  static const octave_int s_zero, s_one;

private:

  T m_ival;
};

template <typename T>
inline octave_int<T>
rem (const octave_int<T>& x, const octave_int<T>& y)
{
  return octave_int_arith<T>::rem (x.value (), y.value ());
}

template <typename T>
inline octave_int<T>
mod (const octave_int<T>& x, const octave_int<T>& y)
{
  return octave_int_arith<T>::mod (x.value (), y.value ());
}

// No mixed integer binary operations!

OCTAVE_BEGIN_NAMESPACE(octave)

OCTAVE_BEGIN_NAMESPACE(math)

    template <typename T>
    bool
    isnan (const octave_int<T>&)
    {
      return false;
    }

OCTAVE_END_NAMESPACE(math)
OCTAVE_END_NAMESPACE(octave)

// FIXME: can/should any of these be inline?

template <typename T>
extern OCTAVE_API octave_int<T>
pow (const octave_int<T>&, const octave_int<T>&);

template <typename T>
extern OCTAVE_API octave_int<T>
pow (const double& a, const octave_int<T>& b);

template <typename T>
extern OCTAVE_API octave_int<T>
pow (const octave_int<T>& a, const double& b);

template <typename T>
extern OCTAVE_API octave_int<T>
pow (const float& a, const octave_int<T>& b);

template <typename T>
extern OCTAVE_API octave_int<T>
pow (const octave_int<T>& a, const float& b);

// FIXME: Do we really need a differently named single-precision
//        function integer power function here instead of an overloaded
//        one?

template <typename T>
extern OCTAVE_API octave_int<T>
powf (const float& a, const octave_int<T>& b);

template <typename T>
extern OCTAVE_API octave_int<T>
powf (const octave_int<T>& a, const float& b);

// Binary relations

#define OCTAVE_INT_CMP_OP(OP, NAME)                                     \
  template <typename T1, typename T2>                                   \
  inline bool                                                           \
  operator OP (const octave_int<T1>& x, const octave_int<T2>& y)        \
  {                                                                     \
    return octave_int_cmp_op::op<octave_int_cmp_op::NAME, T1, T2> (x.value (), y.value ()); \
  }

OCTAVE_INT_CMP_OP (<, lt)
OCTAVE_INT_CMP_OP (<=, le)
OCTAVE_INT_CMP_OP (>, gt)
OCTAVE_INT_CMP_OP (>=, ge)
OCTAVE_INT_CMP_OP (==, eq)
OCTAVE_INT_CMP_OP (!=, ne)

#undef OCTAVE_INT_CMP_OP

template <typename T>
inline std::ostream&
operator << (std::ostream& os, const octave_int<T>& ival)
{
  os << ival.value ();
  return os;
}

template <typename T>
inline std::istream&
operator >> (std::istream& is, octave_int<T>& ival)
{
  T tmp = 0;
  is >> tmp;
  ival = tmp;
  return is;
}

// We need to specialise for char and unsigned char because
// std::operator<< and std::operator>> are overloaded to input and
// output the ASCII character values instead of a representation of
// their numerical value (e.g., os << char(10) outputs a space instead
// of outputting the characters '1' and '0')

template <>
inline std::ostream&
operator << (std::ostream& os, const octave_int<int8_t>& ival)
{
  os << static_cast<int> (ival.value ());

  return os;
}

template <>
inline std::ostream&
operator << (std::ostream& os, const octave_int<uint8_t>& ival)
{
  os << static_cast<unsigned int> (ival.value ());

  return os;
}

template <>
inline std::istream&
operator >> (std::istream& is, octave_int<int8_t>& ival)
{
  int tmp = 0;
  is >> tmp;
  ival = static_cast<int8_t> (tmp);

  return is;
}

template <>
inline std::istream&
operator >> (std::istream& is, octave_int<uint8_t>& ival)
{
  unsigned int tmp = 0;
  is >> tmp;
  ival = static_cast<uint8_t> (tmp);

  return is;
}

// Bitwise operations

#define OCTAVE_INT_BITCMP_OP(OP)                                \
  template <typename T>                                         \
  octave_int<T>                                                 \
  operator OP (const octave_int<T>& x, const octave_int<T>& y)  \
  {                                                             \
    return x.value () OP y.value ();                            \
  }

OCTAVE_INT_BITCMP_OP (&)
OCTAVE_INT_BITCMP_OP (|)
OCTAVE_INT_BITCMP_OP (^)

#undef OCTAVE_INT_BITCMP_OP

// General bit shift.
template <typename T>
octave_int<T>
bitshift (const octave_int<T>& a, int n,
          const octave_int<T>& mask = std::numeric_limits<T>::max ())
{
  if (n > 0)
    return (a << n) & mask;
  else if (n < 0)
    return (a >> -n) & mask;
  else
    return a & mask;
}

#if defined (OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED)

#  define OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_OP(T, OP)     \
  extern OCTAVE_API T                                           \
  external_double_ ## T ## _ ## OP (double x, T y);             \
                                                                \
  extern OCTAVE_API T                                           \
  external_ ## T ## _double_ ## OP (T x, double y)

#  define OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_OPS(T)        \
  OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_OP (T, add);          \
  OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_OP (T, sub);          \
  OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_OP (T, mul);          \
  OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_OP (T, div)

  OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_OPS (octave_int64);
  OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_OPS (octave_uint64);

#endif

#define OCTAVE_INT_DOUBLE_BIN_OP0(OP)                           \
  template <typename T>                                         \
  inline octave_int<T>                                          \
  operator OP (const octave_int<T>& x, const double& y)         \
  {                                                             \
    return octave_int<T> (static_cast<double> (x) OP y);        \
  }                                                             \
                                                                \
  template <typename T>                                         \
  inline octave_int<T>                                          \
  operator OP (const double& x, const octave_int<T>& y)         \
  {                                                             \
    return octave_int<T> (x OP static_cast<double> (y));        \
  }

#if defined (OCTAVE_INT_USE_LONG_DOUBLE)

// Handle mixed op using long double.

#  if defined (OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED)

#    define OCTAVE_INT_DOUBLE_BIN_OP(OP, NAME)                  \
  OCTAVE_INT_DOUBLE_BIN_OP0(OP)                                 \
                                                                \
  template <>                                                   \
  inline octave_int64                                           \
  operator OP (const double& x, const octave_int64& y)          \
  {                                                             \
    return external_double_octave_int64_ ## NAME (x, y);        \
  }                                                             \
                                                                \
  template <>                                                   \
  inline octave_uint64                                          \
  operator OP (const double& x, const octave_uint64& y)         \
  {                                                             \
    return external_double_octave_uint64_ ## NAME (x, y);       \
  }                                                             \
                                                                \
  template <>                                                   \
  inline octave_int64                                           \
  operator OP (const octave_int64& x, const double& y)          \
  {                                                             \
    return external_octave_int64_double_ ## NAME (x, y);        \
  }                                                             \
                                                                \
  template <>                                                   \
  inline octave_uint64                                          \
  operator OP (const octave_uint64& x, const double& y)         \
  {                                                             \
    return external_octave_uint64_double_ ## NAME (x, y);       \
  }

#  else

#    define OCTAVE_INT_DOUBLE_BIN_OP(OP, NAME)                          \
  OCTAVE_INT_DOUBLE_BIN_OP0(OP)                                         \
                                                                        \
  template <>                                                           \
  inline octave_int64                                                   \
  operator OP (const double& x, const octave_int64& y)                  \
  {                                                                     \
    return octave_int64 (x OP static_cast<long double> (y.value ()));   \
  }                                                                     \
                                                                        \
  template <>                                                           \
  inline octave_uint64                                                  \
  operator OP (const double& x, const octave_uint64& y)                 \
  {                                                                     \
    return octave_uint64 (x OP static_cast<long double> (y.value ()));  \
  }                                                                     \
                                                                        \
  template <>                                                           \
  inline octave_int64                                                   \
  operator OP (const octave_int64& x, const double& y)                  \
  {                                                                     \
    return octave_int64 (static_cast<long double> (x.value ()) OP y);   \
  }                                                                     \
                                                                        \
  template <>                                                           \
  inline octave_uint64                                                  \
  operator OP (const octave_uint64& x, const double& y)                 \
  {                                                                     \
    return octave_uint64 (static_cast<long double> (x.value ()) OP y);  \
  }

#  endif

#else

// External handlers.

#  define OCTAVE_INT_DOUBLE_BIN_OP(OP, NAME)            \
  OCTAVE_INT_DOUBLE_BIN_OP0(OP)                         \
                                                        \
  template <>                                           \
  OCTAVE_API octave_int64                               \
  operator OP (const double&, const octave_int64&);     \
                                                        \
  template <>                                           \
  OCTAVE_API octave_uint64                              \
  operator OP (const double&, const octave_uint64&);    \
                                                        \
  template <>                                           \
  OCTAVE_API octave_int64                               \
  operator OP (const octave_int64&, const double&);     \
                                                        \
  template <>                                           \
  OCTAVE_API octave_uint64                              \
  operator OP (const octave_uint64&, const double&);

#endif

OCTAVE_INT_DOUBLE_BIN_OP (+, add)
OCTAVE_INT_DOUBLE_BIN_OP (-, sub)
OCTAVE_INT_DOUBLE_BIN_OP (*, mul)
OCTAVE_INT_DOUBLE_BIN_OP (/, div)

#undef OCTAVE_INT_DOUBLE_BIN_OP0
#undef OCTAVE_INT_DOUBLE_BIN_OP
#undef OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_OP
#undef OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_OPS

#define OCTAVE_INT_DOUBLE_CMP_OP(OP, NAME)                              \
  template <typename T>                                                 \
  inline bool                                                           \
  operator OP (const octave_int<T>& x, const double& y)                 \
  {                                                                     \
    return octave_int_cmp_op::mop<octave_int_cmp_op::NAME> (x.value (), y); \
  }                                                                     \
                                                                        \
  template <typename T>                                                 \
  inline bool                                                           \
  operator OP (const double& x, const octave_int<T>& y)                 \
  {                                                                     \
    return octave_int_cmp_op::mop<octave_int_cmp_op::NAME> (x, y.value ()); \
  }

OCTAVE_INT_DOUBLE_CMP_OP (<, lt)
OCTAVE_INT_DOUBLE_CMP_OP (<=, le)
OCTAVE_INT_DOUBLE_CMP_OP (>=, ge)
OCTAVE_INT_DOUBLE_CMP_OP (>, gt)
OCTAVE_INT_DOUBLE_CMP_OP (==, eq)
OCTAVE_INT_DOUBLE_CMP_OP (!=, ne)

#undef OCTAVE_INT_DOUBLE_CMP_OP

// Floats are handled by simply converting to doubles.

#define OCTAVE_INT_FLOAT_BIN_OP(OP)             \
  template <typename T>                         \
  inline octave_int<T>                          \
  operator OP (const octave_int<T>& x, float y) \
  {                                             \
    return x OP static_cast<double> (y);        \
  }                                             \
                                                \
  template <typename T>                         \
  inline octave_int<T>                          \
  operator OP (float x, const octave_int<T>& y) \
  {                                             \
    return static_cast<double> (x) OP y;        \
  }

OCTAVE_INT_FLOAT_BIN_OP (+)
OCTAVE_INT_FLOAT_BIN_OP (-)
OCTAVE_INT_FLOAT_BIN_OP (*)
OCTAVE_INT_FLOAT_BIN_OP (/)

#undef OCTAVE_INT_FLOAT_BIN_OP

#define OCTAVE_INT_FLOAT_CMP_OP(OP) \
  template <typename T>                                 \
  inline bool                                           \
  operator OP (const octave_int<T>& x, const float& y)  \
  {                                                     \
    return x OP static_cast<double> (y);                \
  }                                                     \
                                                        \
  template <typename T>                                 \
  bool                                                  \
  operator OP (const float& x, const octave_int<T>& y)  \
  {                                                     \
    return static_cast<double> (x) OP y;                \
  }

OCTAVE_INT_FLOAT_CMP_OP (<)
OCTAVE_INT_FLOAT_CMP_OP (<=)
OCTAVE_INT_FLOAT_CMP_OP (>=)
OCTAVE_INT_FLOAT_CMP_OP (>)
OCTAVE_INT_FLOAT_CMP_OP (==)
OCTAVE_INT_FLOAT_CMP_OP (!=)

#undef OCTAVE_INT_FLOAT_CMP_OP

template <typename T>
octave_int<T>
xmax (const octave_int<T>& x, const octave_int<T>& y)
{
  const T xv = x.value ();
  const T yv = y.value ();

  return octave_int<T> (xv >= yv ? xv : yv);
}

template <typename T>
octave_int<T>
xmin (const octave_int<T>& x, const octave_int<T>& y)
{
  const T xv = x.value ();
  const T yv = y.value ();

  return octave_int<T> (xv <= yv ? xv : yv);
}

// Ints are handled by converting to octave_int type.

#define OCTAVE_INT_IDX_TYPE_BIN_OP(OP)                          \
  template <typename T>                                         \
  inline octave_int<T>                                          \
  operator OP (const octave_int<T>& x, octave_idx_type y)       \
  {                                                             \
    return x OP octave_int<T> (y);                              \
  }                                                             \
                                                                \
  template <typename T>                                         \
  inline octave_int<T>                                          \
  operator OP (octave_idx_type x, const octave_int<T>& y)       \
  {                                                             \
    return octave_int<T> (x) OP y;                              \
  }

OCTAVE_INT_IDX_TYPE_BIN_OP (+)
OCTAVE_INT_IDX_TYPE_BIN_OP (-)
OCTAVE_INT_IDX_TYPE_BIN_OP (*)
OCTAVE_INT_IDX_TYPE_BIN_OP (/)

#undef OCTAVE_INT_IDX_TYPE_BIN_OP

#endif