Solved

muldiv  long*long/long on 8086

Posted on 1998-05-29
12
398 Views
Last Modified: 2008-02-01
Hello Experts,

I am looking for 64-Bit fixed point arithmetic for 16-Bit compilers (borland)
to implement a  function

long muldiv(long a, long b, long c)   // computing (a*b)/c

The problem is there is no 64 arithmetic for the 16-bit compiler.

Any suggestions are welcome

Thanks in advance.

Michael
 
0
Comment
Question by:m_sauer
  • 4
  • 3
  • 3
  • +1
12 Comments
 
LVL 3

Expert Comment

by:Norbert
ID: 1251049
Answer is comming
0
 
LVL 3

Expert Comment

by:Norbert
ID: 1251050
what about
long muldiv(long a, long b, long c)
{
      return(long)(((double)a*(double)b)/(double)c);
}
this will convert a,b,c to double, calculate the value as double
and convert back to long
0
 
LVL 16

Expert Comment

by:imladris
ID: 1251051
I have a routine (that has been used in a commercial package for years now) that allows for a 48 bit intermediate result (i.e. the multiplication of a and b can be up to 48 bits).
It's not quite the 64 bit intermediate result you asked, on the other hand it is working debugged (Microsoft C) code. It should be easy to adapt. I don't know what kind of numbers you are working with, but 48 bits has been enough in our case.

Let me know if this would be sufficient for your purposes.

0
 
LVL 3

Expert Comment

by:Norbert
ID: 1251052
what about
long muldiv(long a, long b, long c)
{
      return(long)(((double)a*(double)b)/(double)c);
}
this will convert a,b,c to double, calculate the value as double
and convert back to long
0
 
LVL 3

Expert Comment

by:Norbert
ID: 1251053
sorry for duplicate message but the explorer faild the first time
I clicked the submit button
0
 
LVL 10

Expert Comment

by:RONSLOW
ID: 1251054
goto www.snippets.org

they have source code for long integers arithmetic etc.

0
Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
LVL 10

Expert Comment

by:RONSLOW
ID: 1251055
In particular you will find there

|=============================================================================
| Cliff Rhodes' package of unsigned integer math for arbitrarily large numbers
|=============================================================================
| File         O/S  Description
| ------------ ---  ----------------------------------------------------------
  Bignum.H     any  Header declaring the BigNum struct and prototypes
  Bignum1.C    any  Add, subtract, and multiply BigNum's
  Bignum2.C    any  Divide BigNum's
  Bigtest.C    any  Test and demo program using BigNum's

0
 
LVL 10

Expert Comment

by:RONSLOW
ID: 1251056
This is arbitrary precision arithmetic .. not 64 bit.

You may need to go to assembly to get efficient 64bit arithmetic.


0
 

Author Comment

by:m_sauer
ID: 1251057
Norbert,
thanks for your suggestion, but this is not really solving my problem.
Double precision floating point is just to slow on the 80188em processor I am using.
It has to be a pure integer solution, as I was asking for.

Thanks anyway.




0
 

Author Comment

by:m_sauer
ID: 1251058
Imladris

the 48-bit routines would be perfect as my intermediate results will fit into that precision.

Please give me some more information!


0
 
LVL 16

Accepted Solution

by:
imladris earned 300 total points
ID: 1251059
The following code is used under Microsoft version 6.0. If your compiler doesn't have
an inline assembler you can eliminate the _asm portion. It is only there to
provide fast results for the case where both arguments are in fact 16 bits or less.
The type argument controls rounding: 0 is regular, 1 is truncate and 2 is round up.
If all you need is regular rounding, simply eliminate the argument and code associated
with all the types except 0. If there's anything else I can explain, please feel free
to ask.


#define Lo(x)    ((x)&0x0000ffffL)
#define Hi(x)    ((x)>>16)

long rmuldiv(a,b,c,type)
long a,b,c;
char type;

{      int i,sgn;
      unsigned long f;
      unsigned long ih,im,il,rh,rl,r;
      long rnd;
      
      if (type==1) rnd=0;
      else if (type==2) rnd=(c>=0?c-1:c+1);
      else rnd=c>>1;

      if(c==0)return(0);
      if((a&0xffff0000L) && (b&0xffff0000L))goto lsovf;
      _asm
      {      mov      ax,word ptr a+2            ;Hi(a)
            mov      cx,word ptr b+2            ;Hi(b)
            or      cx,ax                        ;if both 0
            mov      cx,word ptr b            ;(Lo(b))
            jnz      fulmul                        ;is false do full multiplication
                                                ;note: fulmul also done for any negative numbers
            mov      ax,word ptr a            ;else Lo(a)
            mul      cx                              ;16 bit multiply with overflow is enough
            jmp      scs                              ;goto finish
            
                                    ;The intermediate results of the hi*lo multiplies
                                    ;will be added in to the upper word of the long
                                    ;result and must therefore be 16 bits or less in order
                                    ;to avoid overflow

sovf:      jmp lsovf
fulmul:      mul      cx                              ;Hi(a) * Lo(b)
            jo      sovf
            mov      bx,ax                        ;save intermediate
            mov      ax,word ptr a            ;Lo(a)
            mul      word ptr b+2            ;Lo(a) * Hi(b)
            jo      sovf
            add      bx,ax                        ;add to intermediate
            jc      sovf
            mov      ax,word ptr a
            mul      cx                              ;Lo(a) * Lo(b)
            add      dx,bx                        ;add intermediate to lo multiply
            jc      sovf
      scs:
            mov      word ptr f,ax
            mov      word ptr f+2,dx
      }

      if(c>=0)return((f+rnd)/c);
      return((f-rnd)/c);

lsovf:
/* resolve sign result beforehand, so that this routine can
   assume working with 2 non-negative quantities
*/
      sgn=1;
      if(a<0)
      {      a=-a;
            sgn*=-1;
      }
      if(b<0)
      {      b=-b;
            sgn*=-1;
      }
      if(c<0)
      {      c=-c;
            rnd=-rnd;
            sgn*=-1;
      }
      
/* multiply 2 longs by multiplying all the words and adding with
   appropriate shifts.
*/
   
      il=Lo(a)*Lo(b);
      im=Lo(a)*Hi(b)+Hi(a)*Lo(b);
      ih=Hi(a)*Hi(b);
      rl=il+(Lo(im)<<16);
      rh=ih+Hi(im)+(Hi(il)+Lo(im)>0x0000ffffL);

/*  Add rnd , which depends on rounding method */

      il=Lo(rl)+Lo(rnd);
      im=Hi(rl)+Hi(rnd)+Hi(il);
      rl=Lo(il)+(im<<16);
      rh+=Hi(im);

/*      This division routine will deal with a 6 byte number
    It essentially starts off by doing long division:
      If we label the bytes 1 2 3 4 5 6 it first divides
      1 2 3 4 by c giving r the result. The intermediate now
      gets the remainder, and the result is shifted up.
      If this remainder is less than 2 bytes we proceed by
      shifting the intermediate result left, orring in the rest
      of the dividend and orring the result in, just like long division.
      If the result is longer than 2 bytes (which implies that the
      divisor is longer than 2 bytes also) then the shifts we did
      before would shift out high order bits in im.
      Therefore these are put in rh. im is shifted up and gets the rest
      of the dividend orred in. The final result is now obtained by
      bitwise long division.
*/

      r=0;
      im=(rh<<16) | ((rl>>16)&0x0000ffffL);
      r=im/c;
      im%=c;
      r<<=16;
      if((im&0xffff0000L)==0)return(sgn*(long)(r | (im<<16 | rl&0x0000ffffL)/c));
      rh=(im>>16)&0x0000ffffL;
      rl=im<<16 | (rl&0x0000ffffL);
      im=0;
      for(i=0; i<32; ++i)
      {      rh<<=1;
            rh|=(rl&0x80000000L?1:0);
            rl<<=1;
            im<<=1;
            if(rh>c)
            {      rh-=c;
                  ++im;
            }
      }
      return(sgn*(long)(r | im));
}

0
 

Author Comment

by:m_sauer
ID: 1251060
imladris,

just assuming your routine works right (it's too tricky to judge form the source ), it is an excellent solution for my problem.

thank you very much for your great help.


0

Featured Post

Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

Have you thought about creating an iPhone application (app), but didn't even know where to get started? Here's how: ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ Important pre-programming comments: I’ve never tri…
Windows programmers of the C/C++ variety, how many of you realise that since Window 9x Microsoft has been lying to you about what constitutes Unicode (http://en.wikipedia.org/wiki/Unicode)? They will have you believe that Unicode requires you to use…
The goal of this video is to provide viewers with basic examples to understand recursion in the C programming language.
Video by: Grant
The goal of this video is to provide viewers with basic examples to understand and use while-loops in the C programming language.

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

20 Experts available now in Live!

Get 1:1 Help Now