overflows.h 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. #if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
  2. #pragma once
  3. #include <c10/macros/Macros.h>
  4. #include <c10/util/TypeSafeSignMath.h>
  5. #include <c10/util/complex.h>
  6. #include <cmath>
  7. #include <limits>
  8. #include <type_traits>
  9. namespace c10 {
  10. // In some versions of MSVC, there will be a compiler error when building.
  11. // C4146: unary minus operator applied to unsigned type, result still unsigned
  12. // C4804: unsafe use of type 'bool' in operation
  13. // It can be addressed by disabling the following warning.
  14. #ifdef _MSC_VER
  15. #pragma warning(push)
  16. #pragma warning(disable : 4146)
  17. #pragma warning(disable : 4804)
  18. #pragma warning(disable : 4018)
  19. #endif
  20. // The overflow checks may involve float to int conversion which may
  21. // trigger precision loss warning. Re-enable the warning once the code
  22. // is fixed. See T58053069.
  23. C10_CLANG_DIAGNOSTIC_PUSH()
  24. #if C10_CLANG_HAS_WARNING("-Wimplicit-float-conversion")
  25. C10_CLANG_DIAGNOSTIC_IGNORE("-Wimplicit-float-conversion")
  26. #endif
  27. // bool can be converted to any type.
  28. // Without specializing on bool, in pytorch_linux_trusty_py2_7_9_build:
  29. // `error: comparison of constant '255' with boolean expression is always false`
  30. // for `f > limit::max()` below
  31. template <typename To, typename From>
  32. std::enable_if_t<std::is_same_v<From, bool>, bool> overflows(
  33. From /*f*/,
  34. bool strict_unsigned [[maybe_unused]] = false) {
  35. return false;
  36. }
  37. // skip isnan and isinf check for integral types
  38. template <typename To, typename From>
  39. std::enable_if_t<std::is_integral_v<From> && !std::is_same_v<From, bool>, bool>
  40. overflows(From f, bool strict_unsigned = false) {
  41. using limit = std::numeric_limits<typename scalar_value_type<To>::type>;
  42. if constexpr (!limit::is_signed && std::numeric_limits<From>::is_signed) {
  43. // allow for negative numbers to wrap using two's complement arithmetic.
  44. // For example, with uint8, this allows for `a - b` to be treated as
  45. // `a + 255 * b`.
  46. if (!strict_unsigned) {
  47. return greater_than_max<To>(f) ||
  48. (c10::is_negative(f) &&
  49. -static_cast<uint64_t>(f) > static_cast<uint64_t>(limit::max()));
  50. }
  51. }
  52. return c10::less_than_lowest<To>(f) || greater_than_max<To>(f);
  53. }
  54. template <typename To, typename From>
  55. std::enable_if_t<std::is_floating_point_v<From>, bool> overflows(
  56. From f,
  57. bool strict_unsigned [[maybe_unused]] = false) {
  58. using limit = std::numeric_limits<typename scalar_value_type<To>::type>;
  59. if (limit::has_infinity && std::isinf(static_cast<double>(f))) {
  60. return false;
  61. }
  62. if (!limit::has_quiet_NaN && (f != f)) {
  63. return true;
  64. }
  65. return f < limit::lowest() || f > limit::max();
  66. }
  67. C10_CLANG_DIAGNOSTIC_POP()
  68. #ifdef _MSC_VER
  69. #pragma warning(pop)
  70. #endif
  71. template <typename To, typename From>
  72. std::enable_if_t<is_complex<From>::value, bool> overflows(
  73. From f,
  74. bool strict_unsigned = false) {
  75. // casts from complex to real are considered to overflow if the
  76. // imaginary component is non-zero
  77. if (!is_complex<To>::value && f.imag() != 0) {
  78. return true;
  79. }
  80. // Check for overflow componentwise
  81. // (Technically, the imag overflow check is guaranteed to be false
  82. // when !is_complex<To>, but any optimizer worth its salt will be
  83. // able to figure it out.)
  84. return overflows<
  85. typename scalar_value_type<To>::type,
  86. typename From::value_type>(f.real(), strict_unsigned) ||
  87. overflows<
  88. typename scalar_value_type<To>::type,
  89. typename From::value_type>(f.imag(), strict_unsigned);
  90. }
  91. } // namespace c10
  92. #else
  93. #error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
  94. #endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)