bn_mp_n_root.c 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. #include <tommath.h>
  2. #ifdef BN_MP_N_ROOT_C
  3. /* LibTomMath, multiple-precision integer library -- Tom St Denis
  4. *
  5. * LibTomMath is a library that provides multiple-precision
  6. * integer arithmetic as well as number theoretic functionality.
  7. *
  8. * The library was designed directly after the MPI library by
  9. * Michael Fromberger but has been written from scratch with
  10. * additional optimizations in place.
  11. *
  12. * The library is free for all purposes without any express
  13. * guarantee it works.
  14. *
  15. * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com
  16. */
  17. /* find the n'th root of an integer
  18. *
  19. * Result found such that (c)**b <= a and (c+1)**b > a
  20. *
  21. * This algorithm uses Newton's approximation
  22. * x[i+1] = x[i] - f(x[i])/f'(x[i])
  23. * which will find the root in log(N) time where
  24. * each step involves a fair bit. This is not meant to
  25. * find huge roots [square and cube, etc].
  26. */
  27. int mp_n_root (mp_int * a, mp_digit b, mp_int * c)
  28. {
  29. mp_int t1, t2, t3;
  30. int res, neg;
  31. /* input must be positive if b is even */
  32. if ((b & 1) == 0 && a->sign == MP_NEG) {
  33. return MP_VAL;
  34. }
  35. if ((res = mp_init (&t1)) != MP_OKAY) {
  36. return res;
  37. }
  38. if ((res = mp_init (&t2)) != MP_OKAY) {
  39. goto LBL_T1;
  40. }
  41. if ((res = mp_init (&t3)) != MP_OKAY) {
  42. goto LBL_T2;
  43. }
  44. /* if a is negative fudge the sign but keep track */
  45. neg = a->sign;
  46. a->sign = MP_ZPOS;
  47. /* t2 = 2 */
  48. mp_set (&t2, 2);
  49. do {
  50. /* t1 = t2 */
  51. if ((res = mp_copy (&t2, &t1)) != MP_OKAY) {
  52. goto LBL_T3;
  53. }
  54. /* t2 = t1 - ((t1**b - a) / (b * t1**(b-1))) */
  55. /* t3 = t1**(b-1) */
  56. if ((res = mp_expt_d (&t1, b - 1, &t3)) != MP_OKAY) {
  57. goto LBL_T3;
  58. }
  59. /* numerator */
  60. /* t2 = t1**b */
  61. if ((res = mp_mul (&t3, &t1, &t2)) != MP_OKAY) {
  62. goto LBL_T3;
  63. }
  64. /* t2 = t1**b - a */
  65. if ((res = mp_sub (&t2, a, &t2)) != MP_OKAY) {
  66. goto LBL_T3;
  67. }
  68. /* denominator */
  69. /* t3 = t1**(b-1) * b */
  70. if ((res = mp_mul_d (&t3, b, &t3)) != MP_OKAY) {
  71. goto LBL_T3;
  72. }
  73. /* t3 = (t1**b - a)/(b * t1**(b-1)) */
  74. if ((res = mp_div (&t2, &t3, &t3, NULL)) != MP_OKAY) {
  75. goto LBL_T3;
  76. }
  77. if ((res = mp_sub (&t1, &t3, &t2)) != MP_OKAY) {
  78. goto LBL_T3;
  79. }
  80. } while (mp_cmp (&t1, &t2) != MP_EQ);
  81. /* result can be off by a few so check */
  82. for (;;) {
  83. if ((res = mp_expt_d (&t1, b, &t2)) != MP_OKAY) {
  84. goto LBL_T3;
  85. }
  86. if (mp_cmp (&t2, a) == MP_GT) {
  87. if ((res = mp_sub_d (&t1, 1, &t1)) != MP_OKAY) {
  88. goto LBL_T3;
  89. }
  90. } else {
  91. break;
  92. }
  93. }
  94. /* reset the sign of a first */
  95. a->sign = neg;
  96. /* set the result */
  97. mp_exch (&t1, c);
  98. /* set the sign of the result */
  99. c->sign = neg;
  100. res = MP_OKAY;
  101. LBL_T3:mp_clear (&t3);
  102. LBL_T2:mp_clear (&t2);
  103. LBL_T1:mp_clear (&t1);
  104. return res;
  105. }
  106. #endif
  107. /* $Source: /cvs/libtom/libtommath/bn_mp_n_root.c,v $ */
  108. /* $Revision: 1.3 $ */
  109. /* $Date: 2006/03/31 14:18:44 $ */