1 1.1 mrg /* mpn_fib2_ui -- calculate Fibonacci numbers. 2 1.1 mrg 3 1.1 mrg THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY. THEY'RE ALMOST 4 1.1 mrg CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN 5 1.1 mrg FUTURE GNU MP RELEASES. 6 1.1 mrg 7 1.1.1.3 mrg Copyright 2001, 2002, 2005, 2009, 2018 Free Software Foundation, Inc. 8 1.1 mrg 9 1.1 mrg This file is part of the GNU MP Library. 10 1.1 mrg 11 1.1 mrg The GNU MP Library is free software; you can redistribute it and/or modify 12 1.1.1.2 mrg it under the terms of either: 13 1.1.1.2 mrg 14 1.1.1.2 mrg * the GNU Lesser General Public License as published by the Free 15 1.1.1.2 mrg Software Foundation; either version 3 of the License, or (at your 16 1.1.1.2 mrg option) any later version. 17 1.1.1.2 mrg 18 1.1.1.2 mrg or 19 1.1.1.2 mrg 20 1.1.1.2 mrg * the GNU General Public License as published by the Free Software 21 1.1.1.2 mrg Foundation; either version 2 of the License, or (at your option) any 22 1.1.1.2 mrg later version. 23 1.1.1.2 mrg 24 1.1.1.2 mrg or both in parallel, as here. 25 1.1 mrg 26 1.1 mrg The GNU MP Library is distributed in the hope that it will be useful, but 27 1.1 mrg WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 28 1.1.1.2 mrg or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 29 1.1.1.2 mrg for more details. 30 1.1 mrg 31 1.1.1.2 mrg You should have received copies of the GNU General Public License and the 32 1.1.1.2 mrg GNU Lesser General Public License along with the GNU MP Library. If not, 33 1.1.1.2 mrg see https://www.gnu.org/licenses/. */ 34 1.1 mrg 35 1.1 mrg #include <stdio.h> 36 1.1 mrg #include "gmp-impl.h" 37 1.1 mrg 38 1.1 mrg /* change this to "#define TRACE(x) x" for diagnostics */ 39 1.1 mrg #define TRACE(x) 40 1.1 mrg 41 1.1 mrg 42 1.1 mrg /* Store F[n] at fp and F[n-1] at f1p. fp and f1p should have room for 43 1.1 mrg MPN_FIB2_SIZE(n) limbs. 44 1.1 mrg 45 1.1 mrg The return value is the actual number of limbs stored, this will be at 46 1.1 mrg least 1. fp[size-1] will be non-zero, except when n==0, in which case 47 1.1 mrg fp[0] is 0 and f1p[0] is 1. f1p[size-1] can be zero, since F[n-1]<F[n] 48 1.1 mrg (for n>0). 49 1.1 mrg 50 1.1.1.3 mrg Notes: F[2k+1] = 4*F[k]^2 - F[k-1]^2 + 2*(-1)^k. 51 1.1 mrg 52 1.1 mrg In F[2k+1] with k even, +2 is applied to 4*F[k]^2 just by ORing into the 53 1.1 mrg low limb. 54 1.1 mrg 55 1.1.1.3 mrg In F[2k+1] with k odd, -2 is applied to F[k-1]^2 just by ORing into the 56 1.1.1.3 mrg low limb. 57 1.1 mrg */ 58 1.1 mrg 59 1.1 mrg mp_size_t 60 1.1 mrg mpn_fib2_ui (mp_ptr fp, mp_ptr f1p, unsigned long int n) 61 1.1 mrg { 62 1.1 mrg mp_size_t size; 63 1.1 mrg unsigned long nfirst, mask; 64 1.1 mrg 65 1.1 mrg TRACE (printf ("mpn_fib2_ui n=%lu\n", n)); 66 1.1 mrg 67 1.1 mrg ASSERT (! MPN_OVERLAP_P (fp, MPN_FIB2_SIZE(n), f1p, MPN_FIB2_SIZE(n))); 68 1.1 mrg 69 1.1 mrg /* Take a starting pair from the table. */ 70 1.1 mrg mask = 1; 71 1.1 mrg for (nfirst = n; nfirst > FIB_TABLE_LIMIT; nfirst /= 2) 72 1.1 mrg mask <<= 1; 73 1.1 mrg TRACE (printf ("nfirst=%lu mask=0x%lX\n", nfirst, mask)); 74 1.1 mrg 75 1.1 mrg f1p[0] = FIB_TABLE ((int) nfirst - 1); 76 1.1 mrg fp[0] = FIB_TABLE (nfirst); 77 1.1 mrg size = 1; 78 1.1 mrg 79 1.1 mrg /* Skip to the end if the table lookup gives the final answer. */ 80 1.1 mrg if (mask != 1) 81 1.1 mrg { 82 1.1 mrg mp_size_t alloc; 83 1.1 mrg mp_ptr xp; 84 1.1 mrg TMP_DECL; 85 1.1 mrg 86 1.1 mrg TMP_MARK; 87 1.1 mrg alloc = MPN_FIB2_SIZE (n); 88 1.1 mrg xp = TMP_ALLOC_LIMBS (alloc); 89 1.1 mrg 90 1.1 mrg do 91 1.1 mrg { 92 1.1 mrg /* Here fp==F[k] and f1p==F[k-1], with k being the bits of n from 93 1.1 mrg n&mask upwards. 94 1.1 mrg 95 1.1 mrg The next bit of n is n&(mask>>1) and we'll double to the pair 96 1.1 mrg fp==F[2k],f1p==F[2k-1] or fp==F[2k+1],f1p==F[2k], according as 97 1.1 mrg that bit is 0 or 1 respectively. */ 98 1.1 mrg 99 1.1 mrg TRACE (printf ("k=%lu mask=0x%lX size=%ld alloc=%ld\n", 100 1.1 mrg n >> refmpn_count_trailing_zeros(mask), 101 1.1 mrg mask, size, alloc); 102 1.1 mrg mpn_trace ("fp ", fp, size); 103 1.1 mrg mpn_trace ("f1p", f1p, size)); 104 1.1 mrg 105 1.1 mrg /* fp normalized, f1p at most one high zero */ 106 1.1 mrg ASSERT (fp[size-1] != 0); 107 1.1 mrg ASSERT (f1p[size-1] != 0 || f1p[size-2] != 0); 108 1.1 mrg 109 1.1 mrg /* f1p[size-1] might be zero, but this occurs rarely, so it's not 110 1.1 mrg worth bothering checking for it */ 111 1.1 mrg ASSERT (alloc >= 2*size); 112 1.1 mrg mpn_sqr (xp, fp, size); 113 1.1 mrg mpn_sqr (fp, f1p, size); 114 1.1 mrg size *= 2; 115 1.1 mrg 116 1.1 mrg /* Shrink if possible. Since fp was normalized there'll be at 117 1.1 mrg most one high zero on xp (and if there is then there's one on 118 1.1 mrg yp too). */ 119 1.1 mrg ASSERT (xp[size-1] != 0 || fp[size-1] == 0); 120 1.1 mrg size -= (xp[size-1] == 0); 121 1.1 mrg ASSERT (xp[size-1] != 0); /* only one xp high zero */ 122 1.1 mrg 123 1.1 mrg /* Calculate F[2k-1] = F[k]^2 + F[k-1]^2. */ 124 1.1 mrg f1p[size] = mpn_add_n (f1p, xp, fp, size); 125 1.1 mrg 126 1.1 mrg /* Calculate F[2k+1] = 4*F[k]^2 - F[k-1]^2 + 2*(-1)^k. 127 1.1 mrg n&mask is the low bit of our implied k. */ 128 1.1.1.3 mrg 129 1.1.1.3 mrg ASSERT ((fp[0] & 2) == 0); 130 1.1.1.3 mrg /* fp is F[k-1]^2 == 0 or 1 mod 4, like all squares. */ 131 1.1.1.3 mrg fp[0] |= (n & mask ? 2 : 0); /* possible -2 */ 132 1.1 mrg #if HAVE_NATIVE_mpn_rsblsh2_n 133 1.1 mrg fp[size] = mpn_rsblsh2_n (fp, fp, xp, size); 134 1.1.1.3 mrg MPN_INCR_U(fp, size + 1, (n & mask ? 0 : 2)); /* possible +2 */ 135 1.1 mrg #else 136 1.1 mrg { 137 1.1 mrg mp_limb_t c; 138 1.1 mrg 139 1.1 mrg c = mpn_lshift (xp, xp, size, 2); 140 1.1 mrg xp[0] |= (n & mask ? 0 : 2); /* possible +2 */ 141 1.1 mrg c -= mpn_sub_n (fp, xp, fp, size); 142 1.1 mrg fp[size] = c; 143 1.1 mrg } 144 1.1 mrg #endif 145 1.1 mrg ASSERT (alloc >= size+1); 146 1.1 mrg size += (fp[size] != 0); 147 1.1 mrg 148 1.1 mrg /* now n&mask is the new bit of n being considered */ 149 1.1 mrg mask >>= 1; 150 1.1 mrg 151 1.1 mrg /* Calculate F[2k] = F[2k+1] - F[2k-1], replacing the unwanted one of 152 1.1 mrg F[2k+1] and F[2k-1]. */ 153 1.1 mrg if (n & mask) 154 1.1 mrg ASSERT_NOCARRY (mpn_sub_n (f1p, fp, f1p, size)); 155 1.1 mrg else { 156 1.1 mrg ASSERT_NOCARRY (mpn_sub_n ( fp, fp, f1p, size)); 157 1.1 mrg 158 1.1 mrg /* Can have a high zero after replacing F[2k+1] with F[2k]. 159 1.1 mrg f1p will have a high zero if fp does. */ 160 1.1 mrg ASSERT (fp[size-1] != 0 || f1p[size-1] == 0); 161 1.1 mrg size -= (fp[size-1] == 0); 162 1.1 mrg } 163 1.1 mrg } 164 1.1 mrg while (mask != 1); 165 1.1 mrg 166 1.1 mrg TMP_FREE; 167 1.1 mrg } 168 1.1 mrg 169 1.1 mrg TRACE (printf ("done size=%ld\n", size); 170 1.1 mrg mpn_trace ("fp ", fp, size); 171 1.1 mrg mpn_trace ("f1p", f1p, size)); 172 1.1 mrg 173 1.1 mrg return size; 174 1.1 mrg } 175