Solved

muldiv  long*long/long on 8086

Posted on 1998-05-29
12
402 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
Netscaler Common Configuration How To guides

If you use NetScaler you will want to see these guides. The NetScaler How To Guides show administrators how to get NetScaler up and configured by providing instructions for common scenarios and some not so common ones.

 
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
 
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

Does Powershell have you tied up in knots?

Managing Active Directory does not always have to be complicated.  If you are spending more time trying instead of doing, then it's time to look at something else. For nearly 20 years, AD admins around the world have used one tool for day-to-day AD management: Hyena. Discover why

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

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…
Summary: This tutorial covers some basics of pointer, pointer arithmetic and function pointer. What is a pointer: A pointer is a variable which holds an address. This address might be address of another variable/address of devices/address of fu…
Video by: Grant
The goal of this video is to provide viewers with basic examples to understand and use nested-loops in the C programming language.
The goal of this video is to provide viewers with basic examples to understand opening and reading files in the C programming language.

813 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

11 Experts available now in Live!

Get 1:1 Help Now