reciprocal.c 1.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
  1. /*
  2. Copyright (c) 2019 tevador
  3. This file is part of RandomX.
  4. RandomX is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. RandomX is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with RandomX. If not, see<http://www.gnu.org/licenses/>.
  14. */
  15. #include "reciprocal.h"
  16. /*
  17. Calculates rcp = 2**x / divisor for highest integer x such that rcp < 2**64.
  18. Equivalent x86 assembly (divisor in rcx):
  19. mov edx, 1
  20. mov r8, rcx
  21. xor eax, eax
  22. bsr rcx, rcx
  23. shl rdx, cl
  24. div r8
  25. ret
  26. */
  27. uint64_t randomx_reciprocal(uint64_t divisor) {
  28. const uint64_t p2exp63 = 1ULL << 63;
  29. uint64_t quotient = p2exp63 / divisor, remainder = p2exp63 % divisor;
  30. unsigned bsr = 0; //highest set bit in divisor
  31. for (uint64_t bit = divisor; bit > 0; bit >>= 1)
  32. bsr++;
  33. for (unsigned shift = 0; shift < bsr; shift++) {
  34. if (remainder >= divisor - remainder) {
  35. quotient = quotient * 2 + 1;
  36. remainder = remainder * 2 - divisor;
  37. }
  38. else {
  39. quotient = quotient * 2;
  40. remainder = remainder * 2;
  41. }
  42. }
  43. return quotient;
  44. }