#!/usr/local/bin/perl # Copyright(C) TAKASUGI Shinji (ts@sf.airnet.ne.jp) binmode STDOUT; $unsigned_scale = 2 ** 32; $signed_scale = 2 ** 31; sub powerOf2Signed { local($shift) = @_; if ($shift == 1) { print " cdq\n", " sub eax, edx\n", " sar eax, $shift\n"; } else { print " cdq\n", " shr edx, ", 32 - $shift, "\n", " add eax, edx\n", " sar eax, $shift\n"; } } print "Content-Type: text/html\n\n"; exit 0 if $ENV{'REQUEST_METHOD'} eq 'HEAD'; foreach (split('&', $ENV{'QUERY_STRING'})) { ($key, $value) = split('=', $_, 2); $value =~ tr/+/ /; $value =~ s/%(..)/pack('C', hex($1))/ge; $param{$key} = $value; } $div = $param{'divisor'}; $errormsg = "Invalid divisor!!\n"; print 'Quick Division on Intel Microprocessors', '
dividend:eax', '
divisor:', $div, '
quotient:eax', '
', "\n";

if (!$div || $div != int($div))
{  print $errormsg;
}
elsif ($div =~ /^\d/)  # unsigned
{  if ($div >= $unsigned_scale)
   {  print $errormsg;
   }
   elsif (!($div & ($div - 1)))   # power of 2
   {  $shift = 0;
      $shift++ while ($div = $div >> 1) > 0;
      $shift && print "    shr  eax, $shift\n";
   }
   elsif ($div >= 0x80000000)
   {  print "    cmp  eax, $div\n",
	    "    sbb  eax, eax\n",
	    "    inc  eax\n";
   }
   else
   {  $shift = 0;
      $remainder = ((2 ** 31 - 1) % $div + 1) * 2 % $div;  # do not exceed integer limit!

      while ($remainder && (2 ** $shift < $div - $remainder))
      {  $shift++;
         $remainder = $remainder * 2 % $div;
      }

      $multiplier = (2 ** (32 + $shift) + ($div - $remainder) % $div) / $div;

      if ($multiplier < $unsigned_scale)
      {  $multiplier = sprintf('%x', $multiplier);
         $multiplier =~ s/^(\D)/0$1/;
         print "    mov  edx, ${multiplier}h\n",
               "    mul  edx\n",
               "    mov  eax, edx\n";
         $shift && print "    shr  eax, $shift\n";
      }
      else
      {  $multiplier = sprintf('%x', $multiplier - $unsigned_scale);
         $multiplier =~ s/^(\D)/0$1/;
         print "    mov  edx, ${multiplier}h\n",
               "    mov  ecx, eax\n",
               "    mul  edx\n",
               "    mov  eax, edx\n",
               "    add  eax, ecx\n";
         if ($shift)
         {  print "    rcr  eax, 1\n";
            $shift >= 2 && print "    shr  eax, ", $shift - 1, "\n";
         }
      }
   }
}
else         # signed
{  $absdiv = abs($div);
   if ($div >= $signed_scale || $div < -$signed_scale)
   {  print $errormsg;
   }
   elsif (!($absdiv & ($absdiv - 1)))   # power of 2
   {  if ($div > 0)  # signed positive
      {  $shift = 0;
         $shift++ while ($absdiv = $absdiv >> 1) > 0;
         $shift && &powerOf2Signed($shift);
      }
      else         # signed negative
      {  $shift = 0;
         $shift++ while ($absdiv = $absdiv >> 1) > 0;
         $shift && &powerOf2Signed($shift);
         print "    neg  eax\n";
      }
   }
   else
   {  $shift = 0;
      $remainder = 2 ** 30 % $absdiv * 2 % $absdiv * 2 % $absdiv; # do not exceed integer limit!

      if ($div > 0)
      {  while (2 ** ($shift + 1) < $absdiv - $remainder)
         {  $shift++;
            $remainder = $remainder * 2 % $absdiv;
         }
      }
      else
      {  while (2 ** ($shift + 1) <= $absdiv - $remainder)
         {  $shift++;
            $remainder = $remainder * 2 % $absdiv;
         }
      }

      $multiplier = (2 ** (32 + $shift) + ($absdiv - $remainder)) / $absdiv;
      $multiplier = ~$multiplier + 1 if $div < 0;

      if ($div > 0 && $multiplier < $signed_scale
          || $div < 0 && $multiplier >= $signed_scale)
      {  $multiplier = sprintf('%x', $multiplier);
         $multiplier =~ s/^(\D)/0$1/;
         print "    mov  edx, ${multiplier}h\n",
               "    imul edx\n",
               "    mov  eax, edx\n",
	       "    sar  edx, 31\n";
         $shift && print "    sar  eax, $shift\n";
	 print "    sub  eax, edx\n";
      }
      else
      {  $multiplier = sprintf('%x', $multiplier);
         $multiplier =~ s/^(\D)/0$1/;
         print "    mov  edx, ${multiplier}h\n",
               "    mov  ecx, eax\n",
               "    imul edx\n",
               "    mov  eax, edx\n",
               "    sar  edx, 31\n",
               $div > 0 ? "    add  eax, ecx\n" : "    sub  eax, ecx\n";

         if ($shift)
         {  print "    rcr  eax, 1\n";
            $shift >= 2 && print "    sar  eax, ", $shift - 1, "\n";
	    print "    sub  eax, edx\n";
         }
      }
   }
}

print '



Return to the input form
', "\n", '
Copyright(C) TAKASUGI Shinji ', '(tssf.airnet.ne.jp)
'; exit 0;