|
|
1.1 ! root 1: .file "wm_sqrt.S" ! 2: /*---------------------------------------------------------------------------+ ! 3: | wm_sqrt.S | ! 4: | | ! 5: | Fixed point arithmetic square root evaluation. | ! 6: | | ! 7: | Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | ! 8: | Australia. E-mail [email protected] | ! 9: | | ! 10: | Call from C as: | ! 11: | void wm_sqrt(FPU_REG *n) | ! 12: | | ! 13: +---------------------------------------------------------------------------*/ ! 14: ! 15: /*---------------------------------------------------------------------------+ ! 16: | wm_sqrt(FPU_REG *n) | ! 17: | returns the square root of n in n. | ! 18: | | ! 19: | Use Newton's method to compute the square root of a number, which must | ! 20: | be in the range [1.0 .. 4.0), to 64 bits accuracy. | ! 21: | Does not check the sign or tag of the argument. | ! 22: | Sets the exponent, but not the sign or tag of the result. | ! 23: | | ! 24: | The guess is kept in %esi:%edi | ! 25: +---------------------------------------------------------------------------*/ ! 26: ! 27: #include "exception.h" ! 28: #include "fpu_asm.h" ! 29: ! 30: ! 31: .data ! 32: /* ! 33: Local storage: ! 34: */ ! 35: .align 4,0 ! 36: accum_2: ! 37: .long 0 // ms word ! 38: accum_1: ! 39: .long 0 ! 40: accum_0: ! 41: .long 0 ! 42: ! 43: sq_2: ! 44: .long 0 // ms word ! 45: sq_1: ! 46: .long 0 ! 47: sq_0: ! 48: .long 0 ! 49: ! 50: .text ! 51: .align 2,144 ! 52: ! 53: .globl wm_sqrt ! 54: ! 55: wm_sqrt: ! 56: pushl %ebp ! 57: movl %esp,%ebp ! 58: pushl %esi ! 59: pushl %edi ! 60: // pushl %ebx ! 61: ! 62: movl PARAM1,%esi ! 63: ! 64: movl SIGH(%esi),%eax ! 65: movl SIGL(%esi),%ecx ! 66: xorl %edx,%edx ! 67: ! 68: // We use a rough linear estimate for the first guess.. ! 69: ! 70: cmpl EXP_BIAS,EXP(%esi) ! 71: jnz L10 ! 72: ! 73: shrl $1,%eax /* arg is in the range [1.0 .. 2.0) */ ! 74: rcrl $1,%ecx ! 75: rcrl $1,%edx ! 76: ! 77: L10: ! 78: // From here on, n is never accessed directly again until it is ! 79: // replaced by the answer. ! 80: ! 81: movl %eax,sq_2 // ms word of n ! 82: movl %ecx,sq_1 ! 83: movl %edx,sq_0 ! 84: ! 85: shrl $1,%eax ! 86: addl $0x40000000,%eax ! 87: movl $0xaaaaaaaa,%ecx ! 88: mull %ecx ! 89: shll $1,%edx /* max result was 7fff... */ ! 90: testl $0x80000000,%edx /* but min was 3fff... */ ! 91: jnz no_adjust ! 92: ! 93: movl $0x80000000,%edx /* round up */ ! 94: ! 95: no_adjust: ! 96: movl %edx,%esi // Our first guess ! 97: ! 98: /* We have now computed (approx) (2 + x) / 3, which forms the basis ! 99: for a few iterations of Newton's method */ ! 100: ! 101: movl sq_2,%ecx // ms word ! 102: ! 103: // From our initial estimate, three iterations are enough to get us ! 104: // to 30 bits or so. This will then allow two iterations at better ! 105: // precision to complete the process. ! 106: ! 107: // Compute (g + n/g)/2 at each iteration (g is the guess). ! 108: shrl $1,%ecx // Doing this first will prevent a divide ! 109: // overflow later. ! 110: ! 111: movl %ecx,%edx ! 112: divl %esi ! 113: shrl $1,%esi ! 114: addl %eax,%esi ! 115: ! 116: movl %ecx,%edx ! 117: divl %esi ! 118: shrl $1,%esi ! 119: addl %eax,%esi ! 120: ! 121: movl %ecx,%edx ! 122: divl %esi ! 123: shrl $1,%esi ! 124: addl %eax,%esi ! 125: ! 126: // Now that an estimate accurate to about 30 bits has been obtained, ! 127: // we improve it to 60 bits or so. ! 128: ! 129: // The strategy from now on is to compute new estimates from ! 130: // guess := guess + (n - guess^2) / (2 * guess) ! 131: ! 132: // First, find the square of the guess ! 133: movl %esi,%eax ! 134: mull %esi ! 135: // guess^2 now in %edx:%eax ! 136: ! 137: movl sq_1,%ecx ! 138: subl %ecx,%eax ! 139: movl sq_2,%ecx // ms word of normalized n ! 140: sbbl %ecx,%edx ! 141: jnc l40 ! 142: ! 143: // subtraction gives a negative result ! 144: // negate the reult before division ! 145: notl %edx ! 146: notl %eax ! 147: addl $1,%eax ! 148: adcl $0,%edx ! 149: ! 150: divl %esi ! 151: movl %eax,%ecx ! 152: ! 153: movl %edx,%eax ! 154: divl %esi ! 155: jmp l45 ! 156: ! 157: l40: ! 158: divl %esi ! 159: movl %eax,%ecx ! 160: ! 161: movl %edx,%eax ! 162: divl %esi ! 163: ! 164: notl %ecx ! 165: notl %eax ! 166: addl $1,%eax ! 167: adcl $0,%ecx ! 168: ! 169: l45: ! 170: sarl $1,%ecx // divide by 2 ! 171: rcrl $1,%eax ! 172: ! 173: movl %eax,%edi ! 174: addl %ecx,%esi ! 175: ! 176: // Now the square root has been computed to better than 60 bits ! 177: ! 178: // Find the square of the guess ! 179: movl %edi,%eax // ls word of guess ! 180: mull %edi ! 181: movl %edx,accum_0 ! 182: ! 183: movl %esi,%eax ! 184: mull %esi ! 185: movl %edx,accum_2 ! 186: movl %eax,accum_1 ! 187: ! 188: movl %edi,%eax ! 189: mull %esi ! 190: addl %eax,accum_0 ! 191: adcl %edx,accum_1 ! 192: adcl $0,accum_2 ! 193: ! 194: movl %esi,%eax ! 195: mull %edi ! 196: addl %eax,accum_0 ! 197: adcl %edx,accum_1 ! 198: adcl $0,accum_2 ! 199: ! 200: // guess^2 now in accum_2:accum_1:accum_0 ! 201: ! 202: movl sq_1,%eax // get normalized n ! 203: subl %eax,accum_1 ! 204: movl sq_2,%eax // ms word of normalized n ! 205: sbbl %eax,accum_2 ! 206: jnc l60 ! 207: ! 208: // subtraction gives a negative result ! 209: // negate the reult before division ! 210: notl accum_0 ! 211: notl accum_1 ! 212: notl accum_2 ! 213: addl $1,accum_0 ! 214: adcl $0,accum_1 ! 215: ! 216: #ifdef PARANOID ! 217: adcl $0,accum_2 // This must be zero ! 218: jz l51 ! 219: ! 220: pushl EX_INTERNAL|0x207 ! 221: call EXCEPTION ! 222: ! 223: l51: ! 224: #endif PARANOID ! 225: ! 226: movl accum_1,%edx ! 227: movl accum_0,%eax ! 228: divl %esi ! 229: movl %eax,%ecx ! 230: ! 231: movl %edx,%eax ! 232: divl %esi ! 233: ! 234: sarl $1,%ecx // divide by 2 ! 235: rcrl $1,%eax ! 236: ! 237: // round the result ! 238: addl $0x80000000,%eax ! 239: adcl $0,%ecx ! 240: ! 241: addl %ecx,%edi ! 242: adcl $0,%esi ! 243: ! 244: jmp l65 ! 245: ! 246: l60: ! 247: movl accum_1,%edx ! 248: movl accum_0,%eax ! 249: divl %esi ! 250: movl %eax,%ecx ! 251: ! 252: movl %edx,%eax ! 253: divl %esi ! 254: ! 255: sarl $1,%ecx // divide by 2 ! 256: rcrl $1,%eax ! 257: ! 258: // round the result ! 259: addl $0x80000000,%eax ! 260: adcl $0,%ecx ! 261: ! 262: subl %ecx,%edi ! 263: sbbl $0,%esi ! 264: ! 265: l65: ! 266: movl PARAM1,%ecx ! 267: ! 268: movl %edi,SIGL(%ecx) ! 269: movl %esi,SIGH(%ecx) ! 270: ! 271: movl EXP_BIAS,EXP(%ecx) /* Result is in [1.0 .. 2.0) */ ! 272: ! 273: // popl %ebx ! 274: popl %edi ! 275: popl %esi ! 276: leave ! 277: ret
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.