GNU Octave 7.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
oct-inttypes.h
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 2004-2022 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
43namespace octave
44{
45 namespace math
46 {
47 inline long double round (long double x)
48 {
49 return std::roundl (x);
50 }
51
52 inline long double isnan (long double x)
53 {
54 return isnan (static_cast<double> (x));
55 }
56 }
57}
58
59#endif
60
61// FIXME: we define this by our own because some compilers, such as
62// MSVC, do not provide std::abs (int64_t) and std::abs (uint64_t). In
63// the future, it should go away in favor of std::abs.
64
65template <typename T>
66inline T
68{
69 return (x >= 0 ? x : -x);
70}
71
72// Query for an integer type of certain sizeof, and signedness.
73
74template <int qsize, bool qsigned>
76{
77public:
78
79 static const bool registered = false;
80
81 // Void shall result in a compile-time error if we attempt to use it
82 // in computations.
83
84 typedef void type;
85};
86
87#define OCTAVE_REGISTER_INT_TYPE(TYPE) \
88 template <> \
89 class query_integer_type<sizeof (TYPE), \
90 std::numeric_limits<TYPE>::is_signed> \
91 { \
92 public: \
93 \
94 static const bool registered = true; \
95 \
96 typedef TYPE type; \
97 }
98
99// No two registered integers can share sizeof and signedness.
108
109#undef OCTAVE_REGISTER_INT_TYPE
110
111// Handles non-homogeneous integer comparisons. Avoids doing useless
112// 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 const bool pint = (sizeof (T1) < sizeof (int)
127 && sizeof (T2) < sizeof (int));
128
129 static const bool t1sig = std::numeric_limits<T1>::is_signed;
130 static const bool t2sig = std::numeric_limits<T2>::is_signed;
131
132 static const bool psig
133 = (pint || (sizeof (T2) > sizeof (T1) && t2sig) || t1sig);
134
135 static const int psize
136 = (pint
137 ? sizeof (int)
138 : (sizeof (T2) > sizeof (T1) ? sizeof (T2) : sizeof (T1)));
139 public:
140
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 {
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 const bool ltval = (0 OP 1); \
189 static const 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 const bool ltval = VALUE; \
213 static const 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 (void) { return std::numeric_limits<T>::min (); }
350 static T max_val (void) { 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 const bool t_is_signed = std::numeric_limits<T>::is_signed;
361 static const bool s_is_signed = std::numeric_limits<S>::is_signed;
362
363 static const int t_size = sizeof (T);
364 static const int s_size = sizeof (S);
365
366 static const bool omit_chk_min
367 = (! s_is_signed || (t_is_signed && t_size >= s_size));
368
369 static const 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>
430{ };
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)
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>
783{
784public:
785
786 typedef T val_type;
787
788 octave_int (void) : 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)
803
804 octave_int (float d)
806
807#if defined (OCTAVE_INT_USE_LONG_DOUBLE)
808
809 octave_int (long double 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
827
828 ~octave_int (void) = default;
829
830 T value (void) const { return m_ival; }
831
832 const unsigned char * iptr (void) const
833 {
834 return reinterpret_cast<const unsigned char *> (& m_ival);
835 }
836
837 bool operator ! (void) const { return ! m_ival; }
838
839 bool bool_value (void) const { return static_cast<bool> (value ()); }
840
841 char char_value (void) const { return static_cast<char> (value ()); }
842
843 double double_value (void) const { return static_cast<double> (value ()); }
844
845 float float_value (void) const { return static_cast<float> (value ()); }
846
847 operator T (void) 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 // Homogeneous binary integer operations.
866#define OCTAVE_INT_BIN_OP(OP, NAME, ARGT) \
867 inline octave_int<T> \
868 operator OP (const ARGT& y) const \
869 { \
870 return octave_int_arith<T>::NAME (m_ival, y); \
871 } \
872 \
873 inline octave_int<T>& \
874 operator OP##= (const ARGT& y) \
875 { \
876 m_ival = octave_int_arith<T>::NAME (m_ival, y); \
877 return *this; \
878 }
879
885 OCTAVE_INT_BIN_OP (<<, lshift, int)
886 OCTAVE_INT_BIN_OP (>>, rshift, int)
887
888#undef OCTAVE_INT_BIN_OP
889
890 static octave_int<T> min (void) { return std::numeric_limits<T>::min (); }
891 static octave_int<T> max (void) { return std::numeric_limits<T>::max (); }
892
893 static int nbits (void) { return std::numeric_limits<T>::digits; }
894
895 static int byte_size (void) { return sizeof (T); }
896
897 static const OCTAVE_API char * type_name ();
898
899 // The following are provided for convenience.
900 static const octave_int s_zero, s_one;
901
902private:
903
905};
906
907template <typename T>
908inline octave_int<T>
910{
911 return octave_int_arith<T>::rem (x.value (), y.value ());
912}
913
914template <typename T>
915inline octave_int<T>
917{
918 return octave_int_arith<T>::mod (x.value (), y.value ());
919}
920
921// No mixed integer binary operations!
922
923namespace octave
924{
925 namespace math
926 {
927 template <typename T>
928 bool
930 {
931 return false;
932 }
933 }
934}
935
936// FIXME: can/should any of these be inline?
937
938template <typename T>
940pow (const octave_int<T>&, const octave_int<T>&);
941
942template <typename T>
944pow (const double& a, const octave_int<T>& b);
945
946template <typename T>
948pow (const octave_int<T>& a, const double& b);
949
950template <typename T>
952pow (const float& a, const octave_int<T>& b);
953
954template <typename T>
956pow (const octave_int<T>& a, const float& b);
957
958// FIXME: Do we really need a differently named single-precision
959// function integer power function here instead of an overloaded
960// one?
961
962template <typename T>
964powf (const float& a, const octave_int<T>& b);
965
966template <typename T>
968powf (const octave_int<T>& a, const float& b);
969
970// Binary relations
971
972#define OCTAVE_INT_CMP_OP(OP, NAME) \
973 template <typename T1, typename T2> \
974 inline bool \
975 operator OP (const octave_int<T1>& x, const octave_int<T2>& y) \
976 { \
977 return octave_int_cmp_op::op<octave_int_cmp_op::NAME, T1, T2> (x.value (), y.value ()); \
978 }
979
986
987#undef OCTAVE_INT_CMP_OP
988
989template <typename T>
990inline std::ostream&
991operator << (std::ostream& os, const octave_int<T>& ival)
992{
993 os << ival.value ();
994 return os;
995}
996
997template <typename T>
998inline std::istream&
999operator >> (std::istream& is, octave_int<T>& ival)
1000{
1001 T tmp = 0;
1002 is >> tmp;
1003 ival = tmp;
1004 return is;
1005}
1006
1007// We need to specialise for char and unsigned char because
1008// std::operator<< and std::operator>> are overloaded to input and
1009// output the ASCII character values instead of a representation of
1010// their numerical value (e.g., os << char(10) outputs a space instead
1011// of outputting the characters '1' and '0')
1012
1013template <>
1014inline std::ostream&
1015operator << (std::ostream& os, const octave_int<int8_t>& ival)
1016{
1017 os << static_cast<int> (ival.value ());
1018
1019 return os;
1020}
1021
1022template <>
1023inline std::ostream&
1024operator << (std::ostream& os, const octave_int<uint8_t>& ival)
1025{
1026 os << static_cast<unsigned int> (ival.value ());
1027
1028 return os;
1029}
1030
1031template <>
1032inline std::istream&
1033operator >> (std::istream& is, octave_int<int8_t>& ival)
1034{
1035 int tmp = 0;
1036 is >> tmp;
1037 ival = static_cast<int8_t> (tmp);
1038
1039 return is;
1040}
1041
1042template <>
1043inline std::istream&
1044operator >> (std::istream& is, octave_int<uint8_t>& ival)
1045{
1046 unsigned int tmp = 0;
1047 is >> tmp;
1048 ival = static_cast<uint8_t> (tmp);
1049
1050 return is;
1051}
1052
1053// Bitwise operations
1054
1055#define OCTAVE_INT_BITCMP_OP(OP) \
1056 template <typename T> \
1057 octave_int<T> \
1058 operator OP (const octave_int<T>& x, const octave_int<T>& y) \
1059 { \
1060 return x.value () OP y.value (); \
1061 }
1062
1066
1067#undef OCTAVE_INT_BITCMP_OP
1068
1069// General bit shift.
1070template <typename T>
1072bitshift (const octave_int<T>& a, int n,
1074{
1075 if (n > 0)
1076 return (a << n) & mask;
1077 else if (n < 0)
1078 return (a >> -n) & mask;
1079 else
1080 return a & mask;
1081}
1082
1083#if defined (OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED)
1084
1085# define OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_OP(T, OP) \
1086 extern OCTAVE_API T \
1087 external_double_ ## T ## _ ## OP (double x, T y); \
1088 \
1089 extern OCTAVE_API T \
1090 external_ ## T ## _double_ ## OP (T x, double y)
1091
1092# define OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_OPS(T) \
1093 OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_OP (T, add); \
1094 OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_OP (T, sub); \
1095 OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_OP (T, mul); \
1096 OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_OP (T, div)
1097
1098 OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_OPS (octave_int64);
1099 OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_OPS (octave_uint64);
1100
1101#endif
1102
1103#define OCTAVE_INT_DOUBLE_BIN_OP0(OP) \
1104 template <typename T> \
1105 inline octave_int<T> \
1106 operator OP (const octave_int<T>& x, const double& y) \
1107 { \
1108 return octave_int<T> (static_cast<double> (x) OP y); \
1109 } \
1110 \
1111 template <typename T> \
1112 inline octave_int<T> \
1113 operator OP (const double& x, const octave_int<T>& y) \
1114 { \
1115 return octave_int<T> (x OP static_cast<double> (y)); \
1116 }
1117
1118#if defined (OCTAVE_INT_USE_LONG_DOUBLE)
1119
1120// Handle mixed op using long double.
1121
1122# if defined (OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED)
1123
1124# define OCTAVE_INT_DOUBLE_BIN_OP(OP, NAME) \
1125 OCTAVE_INT_DOUBLE_BIN_OP0(OP) \
1126 \
1127 template <> \
1128 inline octave_int64 \
1129 operator OP (const double& x, const octave_int64& y) \
1130 { \
1131 return external_double_octave_int64_ ## NAME (x, y); \
1132 } \
1133 \
1134 template <> \
1135 inline octave_uint64 \
1136 operator OP (const double& x, const octave_uint64& y) \
1137 { \
1138 return external_double_octave_uint64_ ## NAME (x, y); \
1139 } \
1140 \
1141 template <> \
1142 inline octave_int64 \
1143 operator OP (const octave_int64& x, const double& y) \
1144 { \
1145 return external_octave_int64_double_ ## NAME (x, y); \
1146 } \
1147 \
1148 template <> \
1149 inline octave_uint64 \
1150 operator OP (const octave_uint64& x, const double& y) \
1151 { \
1152 return external_octave_uint64_double_ ## NAME (x, y); \
1153 }
1154
1155# else
1156
1157# define OCTAVE_INT_DOUBLE_BIN_OP(OP, NAME) \
1158 OCTAVE_INT_DOUBLE_BIN_OP0(OP) \
1159 \
1160 template <> \
1161 inline octave_int64 \
1162 operator OP (const double& x, const octave_int64& y) \
1163 { \
1164 return octave_int64 (x OP static_cast<long double> (y.value ())); \
1165 } \
1166 \
1167 template <> \
1168 inline octave_uint64 \
1169 operator OP (const double& x, const octave_uint64& y) \
1170 { \
1171 return octave_uint64 (x OP static_cast<long double> (y.value ())); \
1172 } \
1173 \
1174 template <> \
1175 inline octave_int64 \
1176 operator OP (const octave_int64& x, const double& y) \
1177 { \
1178 return octave_int64 (static_cast<long double> (x.value ()) OP y); \
1179 } \
1180 \
1181 template <> \
1182 inline octave_uint64 \
1183 operator OP (const octave_uint64& x, const double& y) \
1184 { \
1185 return octave_uint64 (static_cast<long double> (x.value ()) OP y); \
1186 }
1187
1188# endif
1189
1190#else
1191
1192// External handlers.
1193
1194# define OCTAVE_INT_DOUBLE_BIN_OP(OP, NAME) \
1195 OCTAVE_INT_DOUBLE_BIN_OP0(OP) \
1196 \
1197 template <> \
1198 OCTAVE_API octave_int64 \
1199 operator OP (const double&, const octave_int64&); \
1200 \
1201 template <> \
1202 OCTAVE_API octave_uint64 \
1203 operator OP (const double&, const octave_uint64&); \
1204 \
1205 template <> \
1206 OCTAVE_API octave_int64 \
1207 operator OP (const octave_int64&, const double&); \
1208 \
1209 template <> \
1210 OCTAVE_API octave_uint64 \
1211 operator OP (const octave_uint64&, const double&);
1212
1213#endif
1214
1219
1220#undef OCTAVE_INT_DOUBLE_BIN_OP0
1221#undef OCTAVE_INT_DOUBLE_BIN_OP
1222#undef OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_OP
1223#undef OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_OPS
1224
1225#define OCTAVE_INT_DOUBLE_CMP_OP(OP, NAME) \
1226 template <typename T> \
1227 inline bool \
1228 operator OP (const octave_int<T>& x, const double& y) \
1229 { \
1230 return octave_int_cmp_op::mop<octave_int_cmp_op::NAME> (x.value (), y); \
1231 } \
1232 \
1233 template <typename T> \
1234 inline bool \
1235 operator OP (const double& x, const octave_int<T>& y) \
1236 { \
1237 return octave_int_cmp_op::mop<octave_int_cmp_op::NAME> (x, y.value ()); \
1238 }
1239
1246
1247#undef OCTAVE_INT_DOUBLE_CMP_OP
1248
1249// Floats are handled by simply converting to doubles.
1250
1251#define OCTAVE_INT_FLOAT_BIN_OP(OP) \
1252 template <typename T> \
1253 inline octave_int<T> \
1254 operator OP (const octave_int<T>& x, float y) \
1255 { \
1256 return x OP static_cast<double> (y); \
1257 } \
1258 \
1259 template <typename T> \
1260 inline octave_int<T> \
1261 operator OP (float x, const octave_int<T>& y) \
1262 { \
1263 return static_cast<double> (x) OP y; \
1264 }
1265
1270
1271#undef OCTAVE_INT_FLOAT_BIN_OP
1272
1273#define OCTAVE_INT_FLOAT_CMP_OP(OP) \
1274 template <typename T> \
1275 inline bool \
1276 operator OP (const octave_int<T>& x, const float& y) \
1277 { \
1278 return x OP static_cast<double> (y); \
1279 } \
1280 \
1281 template <typename T> \
1282 bool \
1283 operator OP (const float& x, const octave_int<T>& y) \
1284 { \
1285 return static_cast<double> (x) OP y; \
1286 }
1287
1294
1295#undef OCTAVE_INT_FLOAT_CMP_OP
1296
1297template <typename T>
1300{
1301 const T xv = x.value ();
1302 const T yv = y.value ();
1303
1304 return octave_int<T> (xv >= yv ? xv : yv);
1305}
1306
1307template <typename T>
1310{
1311 const T xv = x.value ();
1312 const T yv = y.value ();
1313
1314 return octave_int<T> (xv <= yv ? xv : yv);
1315}
1316
1317// Ints are handled by converting to octave_int type.
1318
1319#define OCTAVE_INT_IDX_TYPE_BIN_OP(OP) \
1320 template <typename T> \
1321 inline octave_int<T> \
1322 operator OP (const octave_int<T>& x, octave_idx_type y) \
1323 { \
1324 return x OP octave_int<T> (y); \
1325 } \
1326 \
1327 template <typename T> \
1328 inline octave_int<T> \
1329 operator OP (octave_idx_type x, const octave_int<T>& y) \
1330 { \
1331 return octave_int<T> (x) OP y; \
1332 }
1333
1338
1339#undef OCTAVE_INT_IDX_TYPE_BIN_OP
1340
1341#endif
charNDArray max(char d, const charNDArray &m)
Definition: chNDArray.cc:230
charNDArray min(char d, const charNDArray &m)
Definition: chNDArray.cc:207
static T rshift(T x, int n)
Definition: oct-inttypes.h:604
static T mul_internal(T x, T y)
Definition: oct-inttypes.h:650
query_integer_type< sizeof(T), false >::type UT
Definition: oct-inttypes.h:571
static T lshift(T x, int n)
Definition: oct-inttypes.h:606
uint64_t mul_internal(uint64_t x, uint64_t y)
static T truncate_int(const S &value)
Definition: oct-inttypes.h:355
static S compute_threshold(S val, T orig_val)
Definition: oct-inttypes.h:399
static OCTAVE_API T convert_real(const S &value)
static T max_val(void)
Definition: oct-inttypes.h:350
static T min_val(void)
Definition: oct-inttypes.h:349
static const bool pint
Definition: oct-inttypes.h:126
static const bool t1sig
Definition: oct-inttypes.h:129
static const bool psig
Definition: oct-inttypes.h:133
static const int psize
Definition: oct-inttypes.h:136
query_integer_type< psize, psig >::type type
Definition: oct-inttypes.h:141
static const bool t2sig
Definition: oct-inttypes.h:130
static bool op(stype x, stype y)
Definition: oct-inttypes.h:160
static bool op(stype x, utype y)
Definition: oct-inttypes.h:165
static bool op(utype x, stype y)
Definition: oct-inttypes.h:170
query_integer_type< size, true >::type stype
Definition: oct-inttypes.h:151
query_integer_type< size, false >::type utype
Definition: oct-inttypes.h:150
static bool op(utype x, utype y)
Definition: oct-inttypes.h:155
static bool op(T1 x, T2 y)
Definition: oct-inttypes.h:228
static bool mop(T x, double y)
Definition: oct-inttypes.h:242
static bool mop(double x, T y)
Definition: oct-inttypes.h:248
static int byte_size(void)
Definition: oct-inttypes.h:895
~octave_int(void)=default
bool operator!(void) const
Definition: oct-inttypes.h:837
octave_int< T > abs() const
Definition: oct-inttypes.h:860
const unsigned char * iptr(void) const
Definition: oct-inttypes.h:832
octave_int(void)
Definition: oct-inttypes.h:788
octave_int(double d)
Definition: oct-inttypes.h:801
static octave_int< T > max(void)
Definition: oct-inttypes.h:891
octave_int(float d)
Definition: oct-inttypes.h:804
octave_int(bool b)
Definition: oct-inttypes.h:814
bool bool_value(void) const
Definition: oct-inttypes.h:839
static octave_int< T > min(void)
Definition: oct-inttypes.h:890
octave_int< T > signum() const
Definition: oct-inttypes.h:861
static const octave_int s_zero
Definition: oct-inttypes.h:900
char char_value(void) const
Definition: oct-inttypes.h:841
static const octave_int s_one
Definition: oct-inttypes.h:900
double double_value(void) const
Definition: oct-inttypes.h:843
float float_value(void) const
Definition: oct-inttypes.h:845
octave_int(T i)
Definition: oct-inttypes.h:790
T value(void) const
Definition: oct-inttypes.h:830
octave_int(const U &i)
Definition: oct-inttypes.h:817
octave_int & operator=(const octave_int< T > &)=default
octave_int(const octave_int< U > &i)
Definition: oct-inttypes.h:821
octave_int(const octave_int< T > &)=default
static const OCTAVE_API char * type_name()
octave_int< T > operator+() const
Definition: oct-inttypes.h:849
static int nbits(void)
Definition: oct-inttypes.h:893
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::complex< double > w(std::complex< double > z, double relerr=0)
bool isnan(bool)
Definition: lo-mappers.h:178
double round(double x)
Definition: lo-mappers.h:136
std::ostream & operator<<(std::ostream &os, const octave_int< T > &ival)
Definition: oct-inttypes.h:991
#define OCTAVE_INT_DOUBLE_BIN_OP(OP, NAME)
octave_int< T > rem(const octave_int< T > &x, const octave_int< T > &y)
Definition: oct-inttypes.h:909
#define OCTAVE_INT_UN_OP(OPNAME, NAME)
Definition: oct-inttypes.h:852
#define OCTAVE_REGISTER_INT_CMP_OP(NM, OP)
Definition: oct-inttypes.h:183
std::istream & operator>>(std::istream &is, octave_int< T > &ival)
Definition: oct-inttypes.h:999
#define OCTAVE_INT_BIN_OP(OP, NAME, ARGT)
Definition: oct-inttypes.h:866
#define OCTAVE_REGISTER_INT_TYPE(TYPE)
Definition: oct-inttypes.h:87
#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)
OCTAVE_API octave_int< T > pow(const octave_int< T > &, const octave_int< T > &)
T octave_int_abs(T x)
Definition: oct-inttypes.h:67
#define OCTAVE_REGISTER_INT_CONST_OP(NM, VALUE)
Definition: oct-inttypes.h:207
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)
Definition: oct-inttypes.h:972
octave_int< T > xmin(const octave_int< T > &x, const octave_int< T > &y)
OCTAVE_API octave_int< T > powf(const float &a, const octave_int< T > &b)
#define OCTAVE_DEFINE_LONG_DOUBLE_INT_CMP_OP(T)
Definition: oct-inttypes.h:314
#define OCTAVE_INT_FLOAT_CMP_OP(OP)
octave_int< T > mod(const octave_int< T > &x, const octave_int< T > &y)
Definition: oct-inttypes.h:916
octave_int< T > xmax(const octave_int< T > &x, const octave_int< T > &y)
static const bool registered
Definition: oct-inttypes.h:79