// Trace info for the Excel 2007 bug 850*77.1+1 = "100001" instead of 65536

// table of divisors, used to extract decimal digits, location:
// .text:301102D0  01 00 00 00 0A 00 00 00  64 00 00 00 E8 03 00 00 
// .text:301102E0  10 27 00 00 FF FF 00 00  
byte DivTbl[] = {
	0x01, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,  // values     1,    10,
	0x64, 0x00, 0x00, 0x00, 0xE8, 0x03, 0x00, 0x00,  // values   100,  1000,
	0x10, 0x27, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00}; // values 10000, 65535,

// table of rounding values, used to get 15 digit accuracy, at .text:300663F7
byte RndTbl[] = 
	{
0x49, 0x68, 0x01, 0x00, // digits = 1
0xE1, 0x12, 0x0E, 0x00, // digits = 2
0xCC, 0xBC, 0x8C, 0x00, // digits = 3
0xF8, 0x5F, 0x7F, 0x05, // digits = 4
0xB3, 0xBF, 0xF9, 0x36, // digits = 5 - this value=0x36F9BFB3
// above seems to be end of table based on Excel 2003 version of table
	};

// Last byte of floating value causes add from table to ECX, 
// the offending six mantissas are exactly those that overflow.
0xFF -> 0xF8000000 + 0x36F9BFB3 = 0x12EF9BFB3
0xFE -> 0xF0000000 + 0x36F9BFB3 = 0x126F9BFB3
0xFD -> 0xE8000000 + 0x36F9BFB3 = 0x11EF9BFB3
0xFC ->	0xE0000000 + 0x36F9BFB3 = 0x116F9BFB3
0xFB -> 0xD8000000 + 0x36F9BFB3 = 0x10EF9BFB3
0xFA -> 0xD0000000 + 0x36F9BFB3 = 0x106F9BFB3
0xF9 ->	0xC8000000 + 0x36F9BFB3 = 0x0FEF9BFB3 // NO CARRY!
0xF8 -> 0xC0000000 + 0x36F9BFB3 = 0x0F6F9BFB3 // NO CARRY!

// Trace of Excel 2007 misformatting 850*77.1+1 = "100001"
// We are formatting a 64-bit IEEE 754 value V=2^e*(1.M)
// The 11-bit exponent E in the bit representation is e+1023.
// the 52 bit mantissa is the fractional part, with an implied
// 1 bit, hence written 1.M
//
// The hex representation of the value V is is 0x40EFFFFF FFFFFFFF

// Initial registers
ST0= 1.0 ST1= 1.0 ST2= 1.0000001192092895508 ST3= 5.9604644775390625e-8 
ST4= 9.9999994039535522461e-1 ST5= 1.0 ST6= 0.0 ST7= 1.0 
CTRL=137F CS=1B DS=23 ES=23 FS=3B GS=0 SS=23 
EAX=FFFE EBX=FFED061E ECX=F EDX=12F4C0 ESI=12F548 EDI=12F9E2 
EBP=12F4C4 ESP=12F49C EFL=202  

// EDI - points to output structure, first entry is output text buffer.
// ESI - points to the hex value for the float.
Format mov  dword ptr [edi+1Eh], 0        // result value - assume 0
       mov  eax, [esi+4]    EAX=40EFFFFF  // high part of double 850*77.1+1
       mov  edx, eax        EDX=40EFFFFF  // store a copy
       and  eax, 7FF00000h  EAX=40E00000  // mask out to get exponent E only
       jz   nullsub_33                    // if 0 exponent (V=0,denormalized)
                                          // so bail out, string then '0'.
       shr  eax, 14h        EAX=40E       // move E to low word
       sub  eax, 3FEh       EAX=10        // subtract 1022, which leaves e+1, 
                                          // e the true exponent
       mov  ebx, eax        EBX=10        // save this: 2^EBX > V
       imul eax, 9A21h      EAX=9A210     // x92A1 = ceil(2^17 * log2)
                                          // this imul gives base 10 exponent 
                                          // in 15.17 fixed point
       sar  eax, 1          EAX=4D108     // now EAX holds signed 16.16 fixed 
                                          // point base 10 exponent
       and  edx, 80000000h  EDX=0         // Get sign into EDX
       add  eax, 40010000h  EAX=4005D108  //
       and  eax, FFFF0000h  EAX=40050000  //
       or   edx, eax        EDX=40050000  // replace sign
       mov  [edi+1Eh], edx                // save value (decimal point place?)
       shr  eax, 10h        EAX=4005      // 
       sub  eax, 4000h      EAX=5         // EAX = # base 10 digits before '.'
                                          // - determines table location later
       or   ebx, ebx        PF=0          // see if exponent < 0 (V < 1) 
       jl   loc_3013C232                  // if so, format using other routine
       cmp  ebx, 10h        PF=1 ZF=1     // is V <= 2^16?
       jle  short Bit16                   // if in this cutoff range, can use
                                          // routine (we can use 16 bit math?)
                                          // else V outside range [0,65536)

Bit16  push edi             ESP=12F498    // save these (used later for digit
       push ecx             ESP=12F494    // counting)
       mov  edx, [esi]      EDX=FFFFFFFF  // get low part of the double value
       mov  esi, [esi+4]    ESI=40EFFFFF  // and the high part
       xchg eax, esi        EAX=40EFFFFF ESI=5 // EAX = V high 32 bits, 
                                          // ESI = number of decimal digits,
                                          // used for table index
       shl  esi, 2          ESI=14        // 4 bytes per divisor table entry
       and  eax, 0FFFFFh    EAX=FFFFF     // EAX = mantissa high bits
       or   eax, 100000h    EAX=1FFFFF    // prepend 1 bit since normalized
       mov  ecx, 15h        ECX=15        // shift so EAX=integer part only
       sub  ecx, ebx        ECX=5         // shift value, move fraction out
       mov  ebx, eax        EBX=1FFFFF    // make a copy for later shift
       shr  eax, cl         EAX=FFFF      // shift out fractional part, 
                                          // EAX = integral part
       neg  cl              ECX=FB        // shift rest of mantissa
       shld ebx, edx, cl    EBX=FFFFFFFF  // low mantissa bits
       shl  edx, cl         EDX=F8000000  // shift bits up...
       mov  ecx, edx        ECX=F8000000  // and place here. Integer in EAX,
                                          // fractional in EBX:ECX
       sub  esi, 4          ESI=10        // divisor table start index
       cmp  eax, DivTbl[esi]              // see if the integral part >= 65535
       jnb  short tag2                    // jump if so 
                                          // (else ESI = ESI-4 omitted)
tag2   test ecx, ecx                      // 
       jz   loc_300664A3                  
       add  ecx, RndTbl[esi] ECX=2EF9BFB3 // adds 0x36F9BFB3, representing
                                          // 2^(-35)+2^(-36)=4.36557*10^-11,
                                          // rounds to 15 decimal digits.
                                          // Overflows exactly those six 
                                          // values ending in 0xFF-0xFA, 
										  // 0xF9 does not carry!
       adc  ebx, 0          EBX=0         // add carry up to EBX, and jump if 
	   jb   tag3                          // carry (means value near integer)

tag3   xor  ecx, ecx        ECX=0         // integer-1 to in EAX, fract in EBX
       mov  edx, 1          EDX=1         // 
       inc  eax             EAX=10000     // carry from EBX into EAX=65536
       jz   skip                          // Excel 2002 jumps here since prev
                                          // instruction was 16-bit inc ax
                                          // Jumping here prints correctly?
       cmp  eax, DivTbl[esi+4]  PF=0      // check against max div value
       jb   loc_300664A3                  // EAX too big?
       jmp  tag4                          // jump to some fixup routine??

tag4   cmp  eax, 0FFFFFFFFh CF=1                       
       jz   Digits                        //
       inc  word ptr [edi+20h]            // move decimal point again
       add  esi, 4          ESI=14        // move table value (incorrect?!)
       jmp  Digits                        // jump to digit printing loop

Digits xor  edx, edx        EDX=0         // EAX=integer, EDX=remainder
skip   div  DivTbl[esi]     EAX=1 EDX=1   // EDX:EAX / 65535 -> 1:1 error!
       or   al, 30h         EAX=31 AF=0   // text for '1' - First digit wrong!
       mov  [edi], al                     // save character here 
       mov  byte ptr [edi+1], 0           // Unicode - 0 here for 2-byte char
       add  edi, 2          EDI=12F9E4    // next char position
       or   edx, edx        PF=0          // see if any remainder
       jz   tag6                          // exit if no remainder
       mov  eax, edx        EAX=1         // move remiander to EAX
       sub  esi, 4          ESI=10        // move divisor table pointer
       ja   short Digits                  // and loop if table not empty

Digits xor  edx, edx        EDX=0 PF=1    // EAX=integer, EDX=remainder
skip   div  DivTbl[esi]     EAX=0 EDX=1   // EDX:EAX / 10000 = 0:1
       or   al, 30h         EAX=30        // text for '0'
       mov  [edi], al                     // save character here 
       mov  byte ptr [edi+1], 0           // Unicode - 0 here for 2-byte char
       add  edi, 2          EDI=12F9E6    // next char position
       or   edx, edx                      // see if any remainder 
       jz   tag6                          // exit if no remainder
       mov  eax, edx        EAX=1         // move remiander to EAX
       sub  esi, 4          ESI=C         // move divisor table pointer
       ja   short Digits                  // and loop if table not empty

Digits xor  edx, edx        EDX=0         // EAX=integer, EDX=remainder
skip   div  DivTbl[esi]     EAX=0 EDX=1   // EDX:EAX / 1000 = 0:1
       or   al, 30h         EAX=30        // text for '0'
       mov  [edi], al                     // save character here 
       mov  byte ptr [edi+1], 0           // Unicode - 0 here for 2-byte char
       add  edi, 2          EDI=12F9E8    // next char position
       or   edx, edx        PF=0          // see if any remainder
       jz   tag6                          // exit if no remainder
       mov  eax, edx        EAX=1         // move remiander to EAX
       sub  esi, 4          ESI=8         // move divisor table pointer
       ja   short Digits                  // and loop if table not empty

Digits xor  edx, edx        EDX=0         // EAX=integer, EDX=remainder
skip   div  DivTbl[esi]     EAX=0 EDX=1   // EDX:EAX / 100 = 0:1
       or   al, 30h         EAX=30        // text for '0'
       mov  [edi], al                     // save character here 
       mov  byte ptr [edi+1], 0           // Unicode - 0 here for 2-byte char
       add  edi, 2          EDI=12F9EA    // next char position
       or   edx, edx                      // see if any remainder
       jz   tag6                          // exit if no remainder
       mov  eax, edx        EAX=1         // move remiander to EAX
       sub  esi, 4          ESI=4         // move divisor table pointer
       ja   short Digits				  // and loop if table not empty

Digits xor  edx, edx        EDX=0         // EAX=integer, EDX=remainder
skip   div  DivTbl[esi]     EAX=0 EDX=1   // EDX:EAX / 10 = 0:1
       or   al, 30h         EAX=30        // text for '0'
       mov  [edi], al                     // save character here 
       mov  byte ptr [edi+1], 0           // Unicode - 0 here for 2-byte char
       add  edi, 2          EDI=12F9EC    // next char position
       or   edx, edx                      // see if any remainder
       jz   tag6                          // exit if no remainder
       mov  eax, edx        EAX=1         // move remiander to EAX
       sub  esi, 4          ESI=0         // move divisor table pointer
       ja   short Digits				  // table empty, jump not taken

       test eax, 0FFh                     // final digit amount = 255?
       jz   tag6                          
       jmp  tag5                                          
tag5   or   al, 30h         EAX=31        // text for '1'
       mov  [edi], al                     // save character here
       mov  byte ptr [edi+1], 0           // Unicode - 0 here for 2-byte char
       add  edi, 2          EDI=12F9EE    // next char position

tag6   mov  eax, ebx        EAX=0         // fractional part to EAX                
       or   eax, ecx        ZF=1          // ???
       jnz  loc_30150AD8                                                      
       mov  word ptr [edi], 30h ; '0'     // write another '0' character
       pop  ecx             ECX=F ESP=12F498       // clean stack
       pop  ebx             EBX=12F9E2 ESP=12F49C  // clean stack, old EDI
       mov  edx, edi        EDX=12F9EE    // 
       sub  edx, ebx        EDX=C         // number of bytes put onto EDI
       sar  edx, 1          EDX=6         // number of characters written

tag7   mov  eax, [ebx+1Eh]  EAX=40060000  // 
       and  eax, 0FFFF0000h AF=0          //               
       or   eax, edx        EAX=40060006  // info about string just made             
       mov  [ebx+1Eh], eax                // save into some field
       and  eax, 7FFFFFFFh                // chop top?
       sub  eax, 40000000h  EAX=60006     // number of digits written?
       ror  eax, 10h                      // orient for return code
       retn                 ESP=12F4A0    // fini
// end
