Re: Need help converting c code to something Borland can handle

From: Arthur J. O'Dwyer (ajo_at_nospam.andrew.cmu.edu)
Date: 02/20/04


Date: Thu, 19 Feb 2004 19:04:34 -0500 (EST)


On Thu, 19 Feb 2004, Andrew Kennedy wrote:
>
> I would like to convert this for use with my Borland compiler
> which is little old. :-)
>
> I have 3.1 which is rather old, that may be part of the problem
> as this uses 32 bit registers.

  The problem about which Borland is complaining is the code's use
of the non-standard '__int64' identifier. Since Borland doesn't
consider '__int64' special in any way, it's treating it as if you
typed

    typedef unsigned __int64

that is, define a type '__int64' equivalent to 'unsigned (int)';
and then it expects to see either a comma or a semicolon (or I
suppose a parenthesis or open bracket). But the next token is
the identifier 'U64', which doesn't make sense. So it complains.

> There is bound to be a newer stdio.h include file as well I may need
> to download.

  You don't "download" header files; they come with your
implementation. They're part of the C library for your system.

> Borland is saying it expects a comma on the first typedef.

  See above.

  A few notes on your program: When you post code to Usenet, it
should be properly indented. If you use "hard tabs" in your source
code, I have two bits of advice for you: (1) Don't. (2)
http://www.contrib.andrew.cmu.edu/~ajo/free-software/detab.c

> /* undiv.c
>
> Program to determine algorithm, multiplier, and shift factor to be
> used to accomplish unsigned division by a constant divisor. Compile
> with MSVC.
> */

> #include <stdio.h>
  #include <stdlib.h>

> typedef unsigned __int64 U64;
> typedef unsigned long U32;

  size_t log2(U32 i)
> {
    size_t t = 0;
    while ((i >>= 1) != 0) {
      ++t;
    }
    return t;
> }

> U32 res1, res2;
> U32 l, s, m, a, r, n, t;
  unsigned long d;
> U64 m_low, m_high, j, k;

> int main (void)
> {
> fprintf (stderr, "\n");
> fprintf (stderr, "Unsigned division by constant\n");
> fprintf (stderr, "=============================\n\n");
> fprintf (stderr, "enter divisor: ");
    fflush(stderr);
> scanf ("%lu", &d);
> printf ("\n");
> if (d == 0) goto printed_code;

  A simple 'return 0;' would of course suffice. In the event that
you decide to keep the 'goto', I suggest a more mnemonic label, such
as 'done' or 'finished'. 'printed_code' leaves it unclear whether
"printed" is a verb or an adjective here, and it's not really true
anyway -- you jump there *without* printing any code in this case!

> if (d >= 0x80000000UL) {
> printf ("; dividend: register or memory location\n");
> printf ("\n");
> printf ("CMP dividend, 0%08lXh\n", d);
> printf ("MOV EDX, 0\n");
> printf ("SBB EDX, -1\n");
> printf ("\n");
> printf ("; quotient now in EDX\n");

  Note that you could be using 'puts' instead of 'printf' here,
and saving yourself a lot of typing. But I wouldn't insist on
the change.

> goto printed_code;
> }

> /* Reduce divisor until it becomes odd */
> n = 0;
> t = d;
> while (!(t & 1)) {
> t >>= 1;
> n++;
> }

> if (t==1) {
> if (n==0) {
> printf ("; dividend: register or memory location\n");
> printf ("\n");
> printf ("MOV EDX, dividend\n", n);
> printf ("\n");
> printf ("; quotient now in EDX\n");
> }
> else {
> printf ("; dividend: register or memory location\n");
> printf ("\n");
> printf ("SHR dividend, %d\n", n);
> printf ("\n");
> printf ("; quotient replaced dividend\n");
> }
> goto printed_code;
> }

  This 'goto' is particularly unnatural. A simple 'else' would not
only make the code cleaner, but would express your intent much better.
You want to check if 'd' is a power of two; if so, do one thing;
otherwise, do another. That's what 'if-else' is *made* for!

> /* Generate m, s for algorithm 0. Based on: Granlund, T.; Montgomery,
> P.L.: "Division by Invariant Integers using Multiplication".
> SIGPLAN Notices, Vol. 29, June 1994, page 61.
> */
> l = log2(t) + 1;
> j = (((U64)(0xffffffff)) % ((U64)(t)));

  The casts are unnecessary. 0xffffffff will fit in an unsigned long
just fine. Write this:

    j = 0xffffffffuL % t;

or, if you are assuming 32-bit unsigned longs, you could just say

    j = ULONG_MAX % t;

> k = (((U64)(1)) << (32+l)) / ((U64)(0xffffffff-j));

  Applying the same logic of simplification, the above line should
reduce to something along these lines. Of course, this assumes that
'U64' actually exists, which is not a portable assumption -- especially
when we're talking about an early 32-bit Borland compiler!

    k = ((U64) 1 << (32+l)) / (0xffffffff - j);

> m_low = (((U64)(1)) << (32+l)) / t;
> m_high = ((((U64)(1)) << (32+l)) + k) / t;

> while (((m_low >> 1) < (m_high >> 1)) && (l > 0)) {
      m_low >>= 1;
      m_high >>= 1;
      --l;
> }

> if ((m_high >> 32) == 0) {
      m = m_high;
> s = l;
> a = 0;

  Oh yeah, and just so we're clear on this: l is an awful name for
a variable. Especially if you're going to be using it in this sort
of context, where you assign l to s and 0 to a. Or was it 1 to a
and O to s...?

> }

> /* Generate m, s for algorithm 1. Based on: Magenheimer, D.J.; et al:
> "Integer Multiplication and Division on the HP Precision
    Architecture". IEEE Transactions on Computers, Vol 37, No. 8,
    August 1988, page 980.
> */
> else {
> s = log2(t);
> m_low = ((U64) 1 << (32+s)) / t;
      r = ((U64) 1 << (32+s)) % t;
      m = m_low + (r < 1+(t>>1));
> a = 1;
> }

> /* Reduce multiplier for either algorithm to smallest possible */
> while (!(m&1)) {
> m = m >> 1;
> s--;
> }
>
> /* Adjust multiplier for reduction of even divisors */
> s += n;
> if (a) {
> printf ("; dividend: register other than EAX or memory location\n");
> printf ("\n");
> printf ("MOV EAX, 0%08lXh\n", m);
> printf ("MUL dividend\n");
> printf ("ADD EAX, 0%08lXh\n", m);
> printf ("ADC EDX, 0\n");
> if (s) printf ("SHR EDX, %d\n", s);

  Whoops! Check those types!

      if (s) printf ("SHR EDX, %lu\n", s);

> printf ("\n");
> printf ("; quotient now in EDX\n");
> }
> else {
> printf ("; dividend: register other than EAX or memory location\n");
> printf ("\n");
> printf ("MOV EAX, 0%08lXh\n", m);
> printf ("MUL dividend\n");
      if (s) printf ("SHR EDX, %lu\n", s);
> printf ("\n");
> printf ("; quotient now in EDX\n");
> }
> printed_code:
> fprintf(stderr, "\n");
    return 0;
> }

  Anyway, the code's really icky, but assuming you actually have
a 64-bit unsigned type, it should be good to go. It would be a
good exercise for you to modify the algorithm so that it doesn't
need a 64-bit type at any point; then you wouldn't even need to
solve this Borland problem!

> Thanks,
> Andrew Kennedy
>
> "It's the start that stops most people."

  On Usenet, you should set off your signature (the thing with the
quotes and rubbish in it) from the rest of your post with two hyphens
and a space on a line by themselves, like this:

-Arthur

-- 
This is a sample signature.
Note the space after the two dashes.
It's very important.


Relevant Pages

  • Re: Floating Point Formats are not linked
    ... and why this error" Floating point formats are not linked" usually ... It seems to be a bug in the Borland compiler. ... Borland has had this bug for a million years or so. ...
    (comp.lang.c)
  • Re: Missing Graph.h and (Graph.lib) woes - any help
    ... > I am trying to compile an old C code written for the Borland Compiler on ... If Turbo C, you're in luck, because Borland ship a complete ... again doesn't cost any actual money). ...
    (comp.lang.c)
  • Re: Missing Graph.h and (Graph.lib) woes - any help
    ... > I am trying to compile an old C code written for the Borland Compiler on ... If Turbo C, you're in luck, because Borland ship a complete ... again doesn't cost any actual money). ...
    (microsoft.public.games)
  • Re: Learning borland.
    ... > borland builder and they won't run. ... How can I start writing simple ... I have no problem getting the Borland compiler to ...
    (alt.comp.lang.learn.c-cpp)