_arithmetic.py 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. # Copyright (c) "Neo4j"
  2. # Neo4j Sweden AB [https://neo4j.com]
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # https://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. from typing import (
  16. Tuple,
  17. TypeVar,
  18. )
  19. __all__ = [
  20. "nano_add",
  21. "nano_div",
  22. "nano_divmod",
  23. "round_half_to_even",
  24. "symmetric_divmod",
  25. ]
  26. def nano_add(x, y):
  27. """
  28. Add with nanosecond precission.
  29. >>> 0.7 + 0.2
  30. 0.8999999999999999
  31. >>> -0.7 + 0.2
  32. -0.49999999999999994
  33. >>> nano_add(0.7, 0.2)
  34. 0.9
  35. >>> nano_add(-0.7, 0.2)
  36. -0.5
  37. :param x:
  38. :param y:
  39. :returns:
  40. """
  41. return (int(1000000000 * x) + int(1000000000 * y)) / 1000000000
  42. def nano_div(x, y):
  43. """
  44. Div with nanosecond precission.
  45. >>> 0.7 / 0.2
  46. 3.4999999999999996
  47. >>> -0.7 / 0.2
  48. -3.4999999999999996
  49. >>> nano_div(0.7, 0.2)
  50. 3.5
  51. >>> nano_div(-0.7, 0.2)
  52. -3.5
  53. :param x:
  54. :param y:
  55. :returns:
  56. """
  57. return float(1000000000 * x) / int(1000000000 * y)
  58. def nano_divmod(x, y):
  59. """
  60. Divmod with nanosecond precission.
  61. >>> divmod(0.7, 0.2)
  62. (3.0, 0.09999999999999992)
  63. >>> nano_divmod(0.7, 0.2)
  64. (3, 0.1)
  65. :param x:
  66. :param y:
  67. :returns:
  68. """
  69. number = type(x)
  70. nx = int(1000000000 * x)
  71. ny = int(1000000000 * y)
  72. q, r = divmod(nx, ny)
  73. return int(q), number(r / 1000000000)
  74. _TDividend = TypeVar("_TDividend", int, float)
  75. def symmetric_divmod(
  76. dividend: _TDividend, divisor: float
  77. ) -> Tuple[int, _TDividend]:
  78. number = type(dividend)
  79. if dividend >= 0:
  80. quotient, remainder = divmod(dividend, divisor)
  81. return int(quotient), number(remainder)
  82. else:
  83. quotient, remainder = divmod(-dividend, divisor)
  84. return -int(quotient), -number(remainder)
  85. def round_half_to_even(n):
  86. """
  87. Round x.5 towards the nearest even integer.
  88. >>> round_half_to_even(3)
  89. 3
  90. >>> round_half_to_even(3.2)
  91. 3
  92. >>> round_half_to_even(3.5)
  93. 4
  94. >>> round_half_to_even(3.7)
  95. 4
  96. >>> round_half_to_even(4)
  97. 4
  98. >>> round_half_to_even(4.2)
  99. 4
  100. >>> round_half_to_even(4.5)
  101. 4
  102. >>> round_half_to_even(4.7)
  103. 5
  104. :param n:
  105. :returns:
  106. """
  107. ten_n = 10 * n
  108. if ten_n == int(ten_n) and ten_n % 10 == 5:
  109. up = int(n + 0.5)
  110. down = int(n - 0.5)
  111. return up if up % 2 == 0 else down
  112. else:
  113. return int(round(n))