GNU Octave 10.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 
Loading...
Searching...
No Matches
oct-inttypes.h
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 2004-2025 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 (octave_oct_inttypes_h)
27#define octave_oct_inttypes_h 1
28
29#include "octave-config.h"
30
31#include <cmath>
32#include <cstdlib>
33
34#include <iosfwd>
35#include <limits>
36
37#include "lo-mappers.h"
38#include "lo-traits.h"
39#include "oct-inttypes-fwd.h"
40
41#if defined (OCTAVE_INT_USE_LONG_DOUBLE)
42
44
46
47inline long double round (long double x)
48{
49 return std::roundl (x);
50}
51
52inline long double isnan (long double x)
53{
54 return isnan (static_cast<double> (x));
55}
56
57OCTAVE_END_NAMESPACE(math)
58OCTAVE_END_NAMESPACE(octave)
59
60#endif
61
62// FIXME: we define this by our own because some compilers, such as
63// MSVC, do not provide std::abs (int64_t) and std::abs (uint64_t). In
64// the future, it should go away in favor of std::abs.
65
66template <typename T>
67inline T
69{
70 return (x >= 0 ? x : -x);
71}
72
73// Query for an integer type of certain sizeof, and signedness.
74
75template <int qsize, bool qsigned>
77{
78public:
79
80 static const bool registered = false;
81
82 // Void shall result in a compile-time error if we attempt to use it
83 // in computations.
84
85 typedef void type;
86};
87
88#define OCTAVE_REGISTER_INT_TYPE(TYPE) \
89 template <> \
90 class query_integer_type<sizeof (TYPE), \
91 std::numeric_limits<TYPE>::is_signed> \
92 { \
93 public: \
94 \
95 static const bool registered = true; \
96 \
97 typedef TYPE type; \
98 }
99
100// No two registered integers can share sizeof and signedness.
109
110#undef OCTAVE_REGISTER_INT_TYPE
111
112// Handles non-homogeneous integer comparisons. Avoids doing useless tests.
113
115{
116 // This determines a suitable promotion type for T1 when meeting T2
117 // in a binary relation. If promotion to int or T2 is safe, it is
118 // used. Otherwise, the signedness of T1 is preserved and it is
119 // widened if T2 is wider. Notice that if this is applied to both
120 // types, they must end up with equal size.
121
122 template <typename T1, typename T2>
123 class prom
124 {
125 // Promote to int?
126 static constexpr bool s_pint = (sizeof (T1) < sizeof (int)
127 && sizeof (T2) < sizeof (int));
128
129 static constexpr bool s_t1sig = std::numeric_limits<T1>::is_signed;
130 static constexpr bool s_t2sig = std::numeric_limits<T2>::is_signed;
131
132 static constexpr bool s_psig
133 = (s_pint || (sizeof (T2) > sizeof (T1) && s_t2sig) || s_t1sig);
134
135 static constexpr int s_psize
136 = (s_pint
137 ? sizeof (int)
138 : (sizeof (T2) > sizeof (T1) ? sizeof (T2) : sizeof (T1)));
139 public:
140
141 typedef typename query_integer_type<s_psize, s_psig>::type type;
142 };
143
144 // Implements comparisons between two types of equal size but
145 // possibly different signedness.
146
147 template <typename xop, int size>
148 class uiop
149 {
150 typedef typename query_integer_type<size, false>::type utype;
151 typedef typename query_integer_type<size, true>::type stype;
152
153 public:
154
155 static bool op (utype x, utype y)
156 {
157 return xop::op (x, y);
158 }
159
160 static bool op (stype x, stype y)
161 {
162 return xop::op (x, y);
163 }
164
165 static bool op (stype x, utype y)
166 {
167 return (x < 0) ? xop::ltval : xop::op (static_cast<utype> (x), y);
168 }
169
170 static bool op (utype x, stype y)
171 {
172 return (y < 0) ? xop::gtval : xop::op (x, static_cast<utype> (y));
173 }
174 };
175
176public:
177
178 // Rationale: Comparators have a single static method, rel(), that
179 // returns the result of the binary relation. They also have two
180 // static boolean fields: ltval, gtval determine the value of x OP y
181 // if x < y, x > y, respectively.
182
183#define OCTAVE_REGISTER_INT_CMP_OP(NM, OP) \
184 class NM \
185 { \
186 public: \
187 \
188 static constexpr bool ltval = (0 OP 1); \
189 static constexpr bool gtval = (1 OP 0); \
190 \
191 template <typename T> \
192 static bool op (T x, T y) { return x OP y; } \
193 }
194
201
202#undef OCTAVE_REGISTER_INT_CMP_OP
203
204 // We also provide two special relations: ct, yielding always true,
205 // and cf, yielding always false.
206
207#define OCTAVE_REGISTER_INT_CONST_OP(NM, VALUE) \
208 class NM \
209 { \
210 public: \
211 \
212 static constexpr bool ltval = VALUE; \
213 static constexpr bool gtval = VALUE; \
214 \
215 template <typename T> \
216 static bool op (T, T) { return VALUE; } \
217 }
218
221
222#undef OCTAVE_REGISTER_INT_CONST_OP
223
224 // Universal comparison operation.
225
226 template <typename xop, typename T1, typename T2>
227 static bool
228 op (T1 x, T2 y)
229 {
230 typedef typename prom<T1, T2>::type PT1;
231 typedef typename prom<T2, T1>::type PT2;
232
233 return uiop<xop, sizeof (PT1)>::op (static_cast<PT1> (x),
234 static_cast<PT2> (y));
235 }
236
237public:
238
239 // Mixed comparisons.
240
241 template <typename xop, typename T>
242 static bool mop (T x, double y)
243 {
244 return xop::op (static_cast<double> (x), y);
245 }
246
247 template <typename xop, typename T>
248 static bool mop (double x, T y)
249 {
250 return xop::op (x, static_cast<double> (y));
251 }
252
253#if defined (OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED)
254
255# define OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_CMP_OPS(T) \
256 template <typename xop> \
257 static OCTAVE_API bool external_mop (double, T); \
258 \
259 template <typename xop> \
260 static OCTAVE_API bool external_mop (T, double)
261
262 OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_CMP_OPS (int64_t);
263 OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_CMP_OPS (uint64_t);
264
265#endif
266
267 // Typecasting to doubles won't work properly for 64-bit integers --
268 // they lose precision. If we have long doubles, use them...
269
270#if defined (OCTAVE_INT_USE_LONG_DOUBLE)
271
272# if defined (OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED)
273
274# define OCTAVE_DEFINE_LONG_DOUBLE_INT_CMP_OP(T) \
275 template <typename xop> \
276 static bool mop (double x, T y) \
277 { \
278 return external_mop<xop> (x, y); \
279 } \
280 \
281 template <typename xop> \
282 static bool mop (T x, double y) \
283 { \
284 return external_mop<xop> (x, y); \
285 }
286
287# else
288
289# define OCTAVE_DEFINE_LONG_DOUBLE_INT_CMP_OP(T) \
290 template <typename xop> \
291 static bool mop (double x, T y) \
292 { \
293 return xop::op (static_cast<long double> (x), \
294 static_cast<long double> (y)); \
295 } \
296 \
297 template <typename xop> \
298 static bool mop (T x, double y) \
299 { \
300 return xop::op (static_cast<long double> (x), \
301 static_cast<long double> (y)); \
302 }
303
304# endif
305
306#else
307
308 // ... otherwise, use external handlers
309
310 // FIXME: We could declare directly the mop methods as external, but
311 // we can't do this because bugs in gcc (<= 4.3) prevent explicit
312 // instantiations later in that case.
313
314# define OCTAVE_DEFINE_LONG_DOUBLE_INT_CMP_OP(T) \
315 template <typename xop> \
316 static OCTAVE_API bool emulate_mop (double, T); \
317 \
318 template <typename xop> \
319 static bool mop (double x, T y) \
320 { \
321 return emulate_mop<xop> (x, y); \
322 } \
323 \
324 template <typename xop> \
325 static OCTAVE_API bool emulate_mop (T, double); \
326 \
327 template <typename xop> \
328 static bool mop (T x, double y) \
329 { \
330 return emulate_mop<xop> (x, y); \
331 }
332
333#endif
334
337
338#undef OCTAVE_DEFINE_LONG_DOUBLE_INT_CMP_OP
339};
340
341// Base integer class. No data, just conversion methods and exception
342// flags.
343
344template <typename T>
346{
347public:
348
349 static T min_val () { return std::numeric_limits<T>::min (); }
350 static T max_val () { return std::numeric_limits<T>::max (); }
351
352 // Convert integer value.
353
354 template <typename S>
355 static T truncate_int (const S& value)
356 {
357 // An exhaustive test whether the max and/or min check can be
358 // omitted.
359
360 static constexpr bool t_is_signed = std::numeric_limits<T>::is_signed;
361 static constexpr bool s_is_signed = std::numeric_limits<S>::is_signed;
362
363 static constexpr int t_size = sizeof (T);
364 static constexpr int s_size = sizeof (S);
365
366 static constexpr bool omit_chk_min
367 = (! s_is_signed || (t_is_signed && t_size >= s_size));
368
369 static constexpr bool omit_chk_max
370 = (t_size > s_size
371 || (t_size == s_size && (! t_is_signed || s_is_signed)));
372
373 // If the check can be omitted, substitute constant false
374 // relation.
375
376 typedef octave_int_cmp_op::cf cf;
377 typedef octave_int_cmp_op::lt lt;
378 typedef octave_int_cmp_op::gt gt;
379 typedef typename if_then_else<omit_chk_min, cf, lt>::result chk_min;
380 typedef typename if_then_else<omit_chk_max, cf, gt>::result chk_max;
381
382 // Efficiency of the following depends on inlining and dead code
383 // elimination, but that should be a piece of cake for most
384 // compilers.
385
386 if (chk_min::op (value, static_cast<S> (min_val ())))
387 return min_val ();
388 else if (chk_max::op (value, static_cast<S> (max_val ())))
389 return max_val ();
390 else
391 return static_cast<T> (value);
392 }
393
394private:
395
396 // Compute a real-valued threshold for a max/min check.
397
398 template <typename S>
399 static S compute_threshold (S val, T orig_val)
400 {
401 // Fool optimizations (maybe redundant).
402
403 val = octave::math::round (val);
404
405 // If val is even, but orig_val is odd, we're one unit off.
406
407 if (orig_val % 2 && val / 2 == octave::math::round (val / 2))
408 // FIXME: is this always correct?
409 val *= (static_cast<S> (1) - (std::numeric_limits<S>::epsilon () / 2));
410
411 return val;
412 }
413
414public:
415
416 // Convert a real number (check NaN and non-int).
417
418 template <typename S>
419 static OCTAVE_API T convert_real (const S& value);
420};
421
422// Saturated (homogeneous) integer arithmetics. The signed and
423// unsigned implementations are significantly different, so we
424// implement another layer and completely specialize. Arithmetics
425// inherits from octave_int_base so that it can use its exceptions and
426// truncation functions.
427
428template <typename T, bool is_signed>
431
432// Unsigned arithmetics. C++ standard requires it to be modular, so
433// the overflows can be handled efficiently and reliably.
434
435template <typename T>
437{
438public:
439
440 static T abs (T x) { return x; }
441
442 static T signum (T x) { return x ? static_cast<T> (1) : static_cast<T> (0); }
443
444 // Shifts do not overflow.
445
446 static T rshift (T x, int n) { return x >> n; }
447
448 static T lshift (T x, int n) { return x << n; }
449
450 static T minus (T) { return static_cast<T> (0); }
451
452 // The overflow behavior for unsigned integers is guaranteed by
453 // C and C++, so the following should always work.
454
455 static T add (T x, T y)
456 {
457 T u = x + y;
458
459 if (u < x)
461
462 return u;
463 }
464
465 static T sub (T x, T y)
466 {
467 T u = x - y;
468
469 if (u > x)
470 u = 0;
471
472 return u;
473 }
474
475 // Multiplication is done using promotion to wider integer type. If
476 // there is no suitable promotion type, this operation *MUST* be
477 // specialized.
478
479 static T mul (T x, T y) { return mul_internal (x, y); }
480
481 static T mul_internal (T x, T y)
482 {
483 // Promotion type for multiplication (if exists).
484
485 typedef typename query_integer_type<2* sizeof (T), false>::type mptype;
486
487 return octave_int_base<T>::truncate_int (static_cast<mptype> (x)
488 * static_cast<mptype> (y));
489 }
490
491 // Division with rounding to nearest. Note that / and % are
492 // probably computed by a single instruction.
493
494 static T div (T x, T y)
495 {
496 if (y != 0)
497 {
498 T z = x / y;
499 T w = x % y;
500
501 if (w >= y-w)
502 z += 1;
503
504 return z;
505 }
506 else
507 return x ? octave_int_base<T>::max_val () : 0;
508 }
509
510 // Remainder.
511
512 static T rem (T x, T y) { return y != 0 ? x % y : 0; }
513
514 // Modulus. Note the weird y = 0 case for Matlab compatibility.
515
516 static T mod (T x, T y) { return y != 0 ? x % y : x; }
517};
518
519#if defined (OCTAVE_INT_USE_LONG_DOUBLE)
520
521// Handle 64-bit multiply using long double.
522
523# if defined (OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED)
524
525extern OCTAVE_API uint64_t
526octave_external_uint64_uint64_mul (uint64_t, uint64_t);
527
528# endif
529
530template <>
531inline uint64_t
533{
534 uint64_t retval;
535
536 long double p = static_cast<long double> (x) * static_cast<long double> (y);
537
538 if (p > static_cast<long double> (octave_int_base<uint64_t>::max_val ()))
540 else
541 retval = static_cast<uint64_t> (p);
542
543 return retval;
544}
545
546template <>
547inline uint64_t
549{
550# if defined (OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED)
551 return octave_external_uint64_uint64_mul (x, y);
552# else
553 return mul_internal (x, y);
554# endif
555}
556
557#else
558
559// Special handler for 64-bit integer multiply.
560
561template <>
562OCTAVE_API uint64_t
564
565#endif
566
567template <typename T>
569{
570 // The corresponding unsigned type.
571 typedef typename query_integer_type<sizeof (T), false>::type UT;
572
573public:
574
575 // Returns 1 for negative number, 0 otherwise.
576
577 static T __signbit (T x) { return (x < 0) ? 1 : 0; }
578
579 static T abs (T x)
580 {
581 // -INT_MAX is safe because C++ actually allows only three
582 // implementations of integers: sign & magnitude, ones complement
583 // and twos complement. The first test will, with modest
584 // optimizations, evaluate at compile time, and maybe eliminate
585 // the branch completely.
586
590 : ((x < 0) ? -x : x));
591 }
592
593 static T signum (T x)
594 {
595 // With modest optimizations, this will compile without a jump.
596
597 return ((x > 0) ? 1 : 0) - __signbit (x);
598 }
599
600 // FIXME: we do not have an authority what signed shifts should
601 // exactly do, so we define them the easy way. Note that Matlab
602 // does not define signed shifts.
603
604 static T rshift (T x, int n) { return x >> n; }
605
606 static T lshift (T x, int n) { return x << n; }
607
608 // Minus has problems similar to abs.
609
610 static T minus (T x)
611 {
615 : -x);
616 }
617
618 static T add (T x, T y)
619 {
620 // Avoid anything that may overflow.
621
622 return (y < 0
625 : x + y)
628 : x + y));
629 }
630
631 static T sub (T x, T y)
632 {
633 // Avoid anything that may overflow.
634
635 return (y < 0
638 : x - y)
639 : (x < octave_int_base<T>::min_val () + y
641 : x - y));
642 }
643
644 // Multiplication is done using promotion to wider integer type. If
645 // there is no suitable promotion type, this operation *MUST* be
646 // specialized.
647
648 static T mul (T x, T y) { return mul_internal (x, y); }
649
650 static T mul_internal (T x, T y)
651 {
652 // Promotion type for multiplication (if exists).
653
654 typedef typename query_integer_type<2* sizeof (T), true>::type mptype;
655
656 return octave_int_base<T>::truncate_int (static_cast<mptype> (x)
657 * static_cast<mptype> (y));
658 }
659
660 // Division.
661
662 static T div (T x, T y)
663 {
664 T z;
665
666 if (y == 0)
667 {
668 if (x < 0)
670 else if (x != 0)
672 else
673 z = 0;
674 }
675 else if (y < 0)
676 {
677 // This is a special case that overflows as well.
678 if (y == -1 && x == octave_int_base<T>::min_val ())
680 else
681 {
682 z = x / y;
683 // Can't overflow, but std::abs (x) can!
684 T w = -octave_int_abs (x % y);
685 if (w <= y - w)
686 z -= 1 - (__signbit (x) << 1);
687 }
688 }
689 else
690 {
691 z = x / y;
692
693 // FIXME: this is a workaround due to MSVC's absence of
694 // std::abs (int64_t). The call to octave_int_abs can't
695 // overflow, but std::abs (x) can!
696 T w = octave_int_abs (x % y);
697
698 if (w >= y - w)
699 z += 1 - (__signbit (x) << 1);
700 }
701 return z;
702 }
703
704 // Remainder.
705
706 static T rem (T x, T y)
707 {
708 return y != 0 ? x % y : 0;
709 }
710
711 // Modulus. Note the weird y = 0 case for Matlab compatibility.
712
713 static T mod (T x, T y)
714 {
715 if (y != 0)
716 {
717 T r = x % y;
718 return (r == 0) ? 0 : (((r < 0) != (y < 0)) ? r + y : r);
719 }
720 else
721 return x;
722 }
723};
724
725#if defined (OCTAVE_INT_USE_LONG_DOUBLE)
726
727// Handle 64-bit multiply using long double
728
729# if defined (OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED)
730
731extern OCTAVE_API int64_t
732octave_external_int64_int64_mul (int64_t, int64_t);
733
734# endif
735
736template <>
737inline int64_t
739{
740 int64_t retval;
741
742 long double p = static_cast<long double> (x) * static_cast<long double> (y);
743
744 if (p > static_cast<long double> (octave_int_base<int64_t>::max_val ()))
746 else if (p < static_cast<long double> (octave_int_base<int64_t>::min_val ()))
748 else
749 retval = static_cast<int64_t> (p);
750
751 return retval;
752}
753
754template <>
755inline int64_t
757{
758# if defined (OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED)
759 return octave_external_int64_int64_mul (x, y);
760# else
761 return mul_internal (x, y);
762# endif
763}
764
765#else
766
767// Special handler for 64-bit integer multiply.
768
769template <>
770OCTAVE_API int64_t
772
773#endif
774
775// This class simply selects the proper arithmetics.
776template <typename T>
778 : public octave_int_arith_base<T, std::numeric_limits<T>::is_signed>
779{ };
780
781template <typename T>
782class OCTAVE_TEMPLATE_API octave_int : public octave_int_base<T>
783{
784public:
785
786 typedef T val_type;
787
788 octave_int () : m_ival () { }
789
790 octave_int (T i) : m_ival (i) { }
791
792#if defined (OCTAVE_HAVE_OVERLOAD_CHAR_INT8_TYPES)
793
794 // Always treat characters as unsigned.
795 octave_int (char c)
796 : m_ival (octave_int_base<T>::truncate_int (static_cast<unsigned char> (c)))
797 { }
798
799#endif
800
801 octave_int (double d)
802 : m_ival (octave_int_base<T>::convert_real (d)) { }
803
804 octave_int (float d)
805 : m_ival (octave_int_base<T>::convert_real (d)) { }
806
807#if defined (OCTAVE_INT_USE_LONG_DOUBLE)
808
809 octave_int (long double d)
810 : m_ival (octave_int_base<T>::convert_real (d)) { }
811
812#endif
813
814 octave_int (bool b) : m_ival (b) { }
815
816 template <typename U>
817 octave_int (const U& i)
818 : m_ival(octave_int_base<T>::truncate_int (i)) { }
819
820 template <typename U>
822 : m_ival (octave_int_base<T>::truncate_int (i.value ())) { }
823
824 octave_int (const octave_int<T>&) = default;
825
826 octave_int& operator = (const octave_int<T>&) = default;
827
828 ~octave_int () = default;
829
830 T value () const { return m_ival; }
831
832 const unsigned char * iptr () const
833 {
834 return reinterpret_cast<const unsigned char *> (& m_ival);
835 }
836
837 bool operator ! () const { return ! m_ival; }
838
839 bool bool_value () const { return static_cast<bool> (value ()); }
840
841 char char_value () const { return static_cast<char> (value ()); }
842
843 double double_value () const { return static_cast<double> (value ()); }
844
845 float float_value () const { return static_cast<float> (value ()); }
846
847 operator T () const { return value (); }
848
849 octave_int<T> operator + () const { return *this; }
850
851 // unary operators & mappers
852#define OCTAVE_INT_UN_OP(OPNAME, NAME) \
853 inline octave_int<T> \
854 OPNAME () const \
855 { \
856 return octave_int_arith<T>::NAME (m_ival); \
857 }
858
859 OCTAVE_INT_UN_OP (operator -, minus)
862
863#undef OCTAVE_INT_UN_OP
864
865 octave_int<T> operator ~ () const
866 {
867 T bitinv = ~ m_ival;
868 return bitinv;
869 }
870
871 // Homogeneous binary integer operations.
872#define OCTAVE_INT_BIN_OP(OP, NAME, ARGT) \
873 inline octave_int<T> \
874 operator OP (const ARGT& y) const \
875 { \
876 return octave_int_arith<T>::NAME (m_ival, y); \
877 } \
878 \
879 inline octave_int<T>& \
880 operator OP##= (const ARGT& y) \
881 { \
882 m_ival = octave_int_arith<T>::NAME (m_ival, y); \
883 return *this; \
884 }
885
891 OCTAVE_INT_BIN_OP (<<, lshift, int)
892 OCTAVE_INT_BIN_OP (>>, rshift, int)
893
894#undef OCTAVE_INT_BIN_OP
895
896 static octave_int<T> min () { return std::numeric_limits<T>::min (); }
897 static octave_int<T> max () { return std::numeric_limits<T>::max (); }
898
899 static int nbits () { return std::numeric_limits<T>::digits; }
900
901 static int byte_size () { return sizeof (T); }
902
903 static const OCTAVE_API char * type_name ();
904
905 // The following are provided for convenience.
906 static const octave_int s_zero, s_one;
907
908private:
909
910 T m_ival;
911};
912
913template <typename T>
914inline octave_int<T>
916{
917 return octave_int_arith<T>::rem (x.value (), y.value ());
918}
919
920template <typename T>
921inline octave_int<T>
923{
924 return octave_int_arith<T>::mod (x.value (), y.value ());
925}
926
927// No mixed integer binary operations!
928
930
932
933template <typename T>
934bool
936{
937 return false;
938}
939
940OCTAVE_END_NAMESPACE(math)
941OCTAVE_END_NAMESPACE(octave)
942
943// FIXME: can/should any of these be inline?
944
945template <typename T>
947pow (const octave_int<T>&, const octave_int<T>&);
948
949template <typename T>
951pow (const double& a, const octave_int<T>& b);
952
953template <typename T>
955pow (const octave_int<T>& a, const double& b);
956
957template <typename T>
959pow (const float& a, const octave_int<T>& b);
960
961template <typename T>
963pow (const octave_int<T>& a, const float& b);
964
965// FIXME: Do we really need a differently named single-precision
966// function integer power function here instead of an overloaded
967// one?
968
969template <typename T>
971powf (const float& a, const octave_int<T>& b);
972
973template <typename T>
975powf (const octave_int<T>& a, const float& b);
976
977// Binary relations
978
979#define OCTAVE_INT_CMP_OP(OP, NAME) \
980 template <typename T1, typename T2> \
981 inline bool \
982 operator OP (const octave_int<T1>& x, const octave_int<T2>& y) \
983 { \
984 return octave_int_cmp_op::op<octave_int_cmp_op::NAME, T1, T2> (x.value (), y.value ()); \
985 }
986
993
994#undef OCTAVE_INT_CMP_OP
995
996template <typename T>
997inline std::ostream&
998operator << (std::ostream& os, const octave_int<T>& ival)
999{
1000 os << ival.value ();
1001 return os;
1002}
1003
1004template <typename T>
1005inline std::istream&
1006operator >> (std::istream& is, octave_int<T>& ival)
1007{
1008 T tmp = 0;
1009 is >> tmp;
1010 ival = tmp;
1011 return is;
1012}
1013
1014// We need to specialise for char and unsigned char because
1015// std::operator<< and std::operator>> are overloaded to input and
1016// output the ASCII character values instead of a representation of
1017// their numerical value (e.g., os << char(10) outputs a space instead
1018// of outputting the characters '1' and '0')
1019
1020template <>
1021inline std::ostream&
1022operator << (std::ostream& os, const octave_int<int8_t>& ival)
1023{
1024 os << static_cast<int> (ival.value ());
1025
1026 return os;
1027}
1028
1029template <>
1030inline std::ostream&
1031operator << (std::ostream& os, const octave_int<uint8_t>& ival)
1032{
1033 os << static_cast<unsigned int> (ival.value ());
1034
1035 return os;
1036}
1037
1038template <>
1039inline std::istream&
1040operator >> (std::istream& is, octave_int<int8_t>& ival)
1041{
1042 int tmp = 0;
1043 is >> tmp;
1044 ival = static_cast<int8_t> (tmp);
1045
1046 return is;
1047}
1048
1049template <>
1050inline std::istream&
1051operator >> (std::istream& is, octave_int<uint8_t>& ival)
1052{
1053 unsigned int tmp = 0;
1054 is >> tmp;
1055 ival = static_cast<uint8_t> (tmp);
1056
1057 return is;
1058}
1059
1060// Bitwise operations
1061
1062#define OCTAVE_INT_BITCMP_OP(OP) \
1063 template <typename T> \
1064 octave_int<T> \
1065 operator OP (const octave_int<T>& x, const octave_int<T>& y) \
1066 { \
1067 return x.value () OP y.value (); \
1068 }
1069
1073
1074#undef OCTAVE_INT_BITCMP_OP
1075
1076// General bit shift.
1077template <typename T>
1079bitshift (const octave_int<T>& a, int n,
1080 const octave_int<T>& mask = std::numeric_limits<T>::max ())
1081{
1082 if (n > 0)
1083 return (a << n) & mask;
1084 else if (n < 0)
1085 return (a >> -n) & mask;
1086 else
1087 return a & mask;
1088}
1089
1090#if defined (OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED)
1091
1092# define OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_OP(T, OP) \
1093 extern OCTAVE_API T \
1094 external_double_ ## T ## _ ## OP (double x, T y); \
1095 \
1096 extern OCTAVE_API T \
1097 external_ ## T ## _double_ ## OP (T x, double y)
1098
1099# define OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_OPS(T) \
1100 OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_OP (T, add); \
1101 OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_OP (T, sub); \
1102 OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_OP (T, mul); \
1103 OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_OP (T, div)
1104
1105OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_OPS (octave_int64);
1106OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_OPS (octave_uint64);
1107
1108#endif
1109
1110#define OCTAVE_INT_DOUBLE_BIN_OP0(OP) \
1111 template <typename T> \
1112 inline octave_int<T> \
1113 operator OP (const octave_int<T>& x, const double& y) \
1114 { \
1115 return octave_int<T> (static_cast<double> (x) OP y); \
1116 } \
1117 \
1118 template <typename T> \
1119 inline octave_int<T> \
1120 operator OP (const double& x, const octave_int<T>& y) \
1121 { \
1122 return octave_int<T> (x OP static_cast<double> (y)); \
1123 }
1124
1125#if defined (OCTAVE_INT_USE_LONG_DOUBLE)
1126
1127// Handle mixed op using long double.
1128
1129# if defined (OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED)
1130
1131# define OCTAVE_INT_DOUBLE_BIN_OP(OP, NAME) \
1132 OCTAVE_INT_DOUBLE_BIN_OP0(OP) \
1133 \
1134 template <> \
1135 inline octave_int64 \
1136 operator OP (const double& x, const octave_int64& y) \
1137 { \
1138 return external_double_octave_int64_ ## NAME (x, y); \
1139 } \
1140 \
1141 template <> \
1142 inline octave_uint64 \
1143 operator OP (const double& x, const octave_uint64& y) \
1144 { \
1145 return external_double_octave_uint64_ ## NAME (x, y); \
1146 } \
1147 \
1148 template <> \
1149 inline octave_int64 \
1150 operator OP (const octave_int64& x, const double& y) \
1151 { \
1152 return external_octave_int64_double_ ## NAME (x, y); \
1153 } \
1154 \
1155 template <> \
1156 inline octave_uint64 \
1157 operator OP (const octave_uint64& x, const double& y) \
1158 { \
1159 return external_octave_uint64_double_ ## NAME (x, y); \
1160 }
1161
1162# else
1163
1164# define OCTAVE_INT_DOUBLE_BIN_OP(OP, NAME) \
1165 OCTAVE_INT_DOUBLE_BIN_OP0(OP) \
1166 \
1167 template <> \
1168 inline octave_int64 \
1169 operator OP (const double& x, const octave_int64& y) \
1170 { \
1171 return octave_int64 (x OP static_cast<long double> (y.value ())); \
1172 } \
1173 \
1174 template <> \
1175 inline octave_uint64 \
1176 operator OP (const double& x, const octave_uint64& y) \
1177 { \
1178 return octave_uint64 (x OP static_cast<long double> (y.value ())); \
1179 } \
1180 \
1181 template <> \
1182 inline octave_int64 \
1183 operator OP (const octave_int64& x, const double& y) \
1184 { \
1185 return octave_int64 (static_cast<long double> (x.value ()) OP y); \
1186 } \
1187 \
1188 template <> \
1189 inline octave_uint64 \
1190 operator OP (const octave_uint64& x, const double& y) \
1191 { \
1192 return octave_uint64 (static_cast<long double> (x.value ()) OP y); \
1193 }
1194
1195# endif
1196
1197#else
1198
1199// External handlers.
1200
1201# define OCTAVE_INT_DOUBLE_BIN_OP(OP, NAME) \
1202 OCTAVE_INT_DOUBLE_BIN_OP0(OP) \
1203 \
1204 template <> \
1205 OCTAVE_API octave_int64 \
1206 operator OP (const double&, const octave_int64&); \
1207 \
1208 template <> \
1209 OCTAVE_API octave_uint64 \
1210 operator OP (const double&, const octave_uint64&); \
1211 \
1212 template <> \
1213 OCTAVE_API octave_int64 \
1214 operator OP (const octave_int64&, const double&); \
1215 \
1216 template <> \
1217 OCTAVE_API octave_uint64 \
1218 operator OP (const octave_uint64&, const double&);
1219
1220#endif
1221
1226
1227#undef OCTAVE_INT_DOUBLE_BIN_OP0
1228#undef OCTAVE_INT_DOUBLE_BIN_OP
1229#undef OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_OP
1230#undef OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_OPS
1231
1232#define OCTAVE_INT_DOUBLE_CMP_OP(OP, NAME) \
1233 template <typename T> \
1234 inline bool \
1235 operator OP (const octave_int<T>& x, const double& y) \
1236 { \
1237 return octave_int_cmp_op::mop<octave_int_cmp_op::NAME> (x.value (), y); \
1238 } \
1239 \
1240 template <typename T> \
1241 inline bool \
1242 operator OP (const double& x, const octave_int<T>& y) \
1243 { \
1244 return octave_int_cmp_op::mop<octave_int_cmp_op::NAME> (x, y.value ()); \
1245 }
1246
1253
1254#undef OCTAVE_INT_DOUBLE_CMP_OP
1255
1256// Floats are handled by simply converting to doubles.
1257
1258#define OCTAVE_INT_FLOAT_BIN_OP(OP) \
1259 template <typename T> \
1260 inline octave_int<T> \
1261 operator OP (const octave_int<T>& x, float y) \
1262 { \
1263 return x OP static_cast<double> (y); \
1264 } \
1265 \
1266 template <typename T> \
1267 inline octave_int<T> \
1268 operator OP (float x, const octave_int<T>& y) \
1269 { \
1270 return static_cast<double> (x) OP y; \
1271 }
1272
1277
1278#undef OCTAVE_INT_FLOAT_BIN_OP
1279
1280#define OCTAVE_INT_FLOAT_CMP_OP(OP) \
1281 template <typename T> \
1282 inline bool \
1283 operator OP (const octave_int<T>& x, const float& y) \
1284 { \
1285 return x OP static_cast<double> (y); \
1286 } \
1287 \
1288 template <typename T> \
1289 bool \
1290 operator OP (const float& x, const octave_int<T>& y) \
1291 { \
1292 return static_cast<double> (x) OP y; \
1293 }
1294
1301
1302#undef OCTAVE_INT_FLOAT_CMP_OP
1303
1304template <typename T>
1307{
1308 const T xv = x.value ();
1309 const T yv = y.value ();
1310
1311 return octave_int<T> (xv >= yv ? xv : yv);
1312}
1313
1314template <typename T>
1317{
1318 const T xv = x.value ();
1319 const T yv = y.value ();
1320
1321 return octave_int<T> (xv <= yv ? xv : yv);
1322}
1323
1324// Ints are handled by converting to octave_int type.
1325
1326#define OCTAVE_INT_IDX_TYPE_BIN_OP(OP) \
1327 template <typename T> \
1328 inline octave_int<T> \
1329 operator OP (const octave_int<T>& x, octave_idx_type y) \
1330 { \
1331 return x OP octave_int<T> (y); \
1332 } \
1333 \
1334 template <typename T> \
1335 inline octave_int<T> \
1336 operator OP (octave_idx_type x, const octave_int<T>& y) \
1337 { \
1338 return octave_int<T> (x) OP y; \
1339 }
1340
1345
1346#undef OCTAVE_INT_IDX_TYPE_BIN_OP
1347
1348#endif
uint64_t mul_internal(uint64_t x, uint64_t y)
static T truncate_int(const S &value)
static T max_val()
static T min_val()
static T convert_real(const S &value)
static bool op(T1 x, T2 y)
static bool mop(T x, double y)
static bool mop(double x, T y)
static int nbits()
char char_value() const
octave_int(double d)
octave_int(float d)
octave_int(bool b)
T value() const
const unsigned char * iptr() const
double double_value() const
bool bool_value() const
~octave_int()=default
static const octave_int s_one
static const char * type_name()
octave_int(const U &i)
octave_int(const octave_int< U > &i)
static octave_int< T > max()
octave_int(const octave_int< T > &)=default
float float_value() const
static octave_int< T > min()
static int byte_size()
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
T rem(T x, T y)
Definition lo-mappers.h:327
double signum(double x)
Definition lo-mappers.h:229
double round(double x)
Definition lo-mappers.h:136
F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE * d
F77_RET_T const F77_DBLE * x
#define OCTAVE_API
Definition main.in.cc:55
std::ostream & operator<<(std::ostream &os, const octave_int< T > &ival)
#define OCTAVE_INT_DOUBLE_BIN_OP(OP, NAME)
octave_int< T > rem(const octave_int< T > &x, const octave_int< T > &y)
#define OCTAVE_INT_UN_OP(OPNAME, NAME)
#define OCTAVE_REGISTER_INT_CMP_OP(NM, OP)
std::istream & operator>>(std::istream &is, octave_int< T > &ival)
#define OCTAVE_INT_BIN_OP(OP, NAME, ARGT)
#define OCTAVE_REGISTER_INT_TYPE(TYPE)
#define OCTAVE_INT_BITCMP_OP(OP)
#define OCTAVE_INT_IDX_TYPE_BIN_OP(OP)
#define OCTAVE_INT_DOUBLE_CMP_OP(OP, NAME)
#define OCTAVE_INT_FLOAT_BIN_OP(OP)
bool isnan(const octave_int< T > &)
octave_int< T > pow(const octave_int< T > &, const octave_int< T > &)
T octave_int_abs(T x)
#define OCTAVE_REGISTER_INT_CONST_OP(NM, VALUE)
octave_int< T > bitshift(const octave_int< T > &a, int n, const octave_int< T > &mask=std::numeric_limits< T >::max())
#define OCTAVE_INT_CMP_OP(OP, NAME)
octave_int< T > xmin(const octave_int< T > &x, const octave_int< T > &y)
#define OCTAVE_DEFINE_LONG_DOUBLE_INT_CMP_OP(T)
#define OCTAVE_INT_FLOAT_CMP_OP(OP)
octave_int< T > mod(const octave_int< T > &x, const octave_int< T > &y)
octave_int< T > operator+(const octave_int< T > &x, const double &y)
octave_int< T > xmax(const octave_int< T > &x, const octave_int< T > &y)
octave_int< T > powf(const float &a, const octave_int< T > &b)
octave_value operator!(const octave_value &a)
Definition ov.h:1648
static const bool registered