मैं केवल थोड़ा सा स्थानांतरण और जोड़ने का उपयोग करके कैसे गुणा और भाग कर सकता हूं?
मैं केवल थोड़ा सा स्थानांतरण और जोड़ने का उपयोग करके कैसे गुणा और भाग कर सकता हूं?
जवाबों:
जोड़ने और शिफ्ट करने के मामले में गुणा करने के लिए आप दो की शक्तियों द्वारा संख्याओं में से एक का विघटन करना चाहते हैं, जैसे:
21 * 5 = 10101_2 * 101_2 (Initial step)
= 10101_2 * (1 * 2^2 + 0 * 2^1 + 1 * 2^0)
= 10101_2 * 2^2 + 10101_2 * 2^0
= 10101_2 << 2 + 10101_2 << 0 (Decomposed)
= 10101_2 * 4 + 10101_2 * 1
= 10101_2 * 5
= 21 * 5 (Same as initial expression)
(_2
आधार 2 का मतलब है)
जैसा कि आप देख सकते हैं, गुणा को फिर से जोड़ने और शिफ्टिंग में वापस विघटित किया जा सकता है। यह भी है कि गुणन बिट शिफ्ट्स की तुलना में अधिक समय लेता है या जोड़ना - यह बिट्स की संख्या में O (n) के बजाय O (n ^ 2) है। रियल कंप्यूटर सिस्टम (सैद्धांतिक कंप्यूटर सिस्टम के विपरीत) में बिट्स की सीमित संख्या होती है, इसलिए गुणा और शिफ्टिंग की तुलना में गुणा में लगातार कई बार समय लगता है। अगर मुझे सही ढंग से याद है, तो आधुनिक प्रोसेसर, अगर ठीक से पाइपलाइज़ किए गए हैं, तो प्रोसेसर में ALUs (अंकगणितीय इकाइयों) के उपयोग के साथ खिलवाड़ करके, इसके अलावा जितनी जल्दी हो सके गुणा कर सकते हैं।
एंड्रयू टूलूज़ के उत्तर को विभाजन तक बढ़ाया जा सकता है।
पूर्णांक स्थिरांक द्वारा विभाजन हेनरी एस। वॉरेन (ISBN 9780201914658) की पुस्तक "हैकर डिलाइट" में विवरण में माना जाता है।
विभाजन को लागू करने के लिए पहला विचार आधार दो में हर का व्युत्क्रम मान लिखना है।
उदाहरण के लिए,
1/3 = (base-2) 0.0101 0101 0101 0101 0101 0101 0101 0101 .....
तो,
a/3 = (a >> 2) + (a >> 4) + (a >> 6) + ... + (a >> 30)
32-बिट अंकगणित के लिए।
एक स्पष्ट तरीके से शब्दों को मिलाकर हम संचालन की संख्या को कम कर सकते हैं:
b = (a >> 2) + (a >> 4)
b += (b >> 4)
b += (b >> 8)
b += (b >> 16)
विभाजन और अवशेषों की गणना करने के लिए अधिक रोमांचक तरीके हैं।
EDIT1:
यदि ओपी का अर्थ है मनमाना संख्याओं का गुणा और भाग, न कि एक स्थिर संख्या से विभाजन, तो यह धागा उपयोग का हो सकता है: https://stackoverflow.com/a/12699549/1182653
EDIT2:
पूर्णांक स्थिरांक द्वारा विभाजित करने का सबसे तेज़ तरीका मॉड्यूलर अंकगणित और मोंटगोमरी कटौती का फायदा उठाना है: पूर्णांक को 3 से विभाजित करने का सबसे तेज़ तरीका क्या है?
b += r * 11 >> 5
साथ r = a - q * 3
। लिंक: hackersdelight.org/divcMore.pdf पेज 2+।
X * 2 = 1 बिट शिफ्ट लेफ्ट
X / 2 = 1 बिट शिफ्ट राईट
X * 3 = शिफ्ट लेफ्ट 1 बिट और फिर X जोड़ें
add X
उस आखिरी के लिए मायने रखते हैं ?
x << k == x multiplied by 2 to the power of k
x >> k == x divided by 2 to the power of k
आप इन पारियों का उपयोग किसी भी गुणन ऑपरेशन को करने के लिए कर सकते हैं। उदाहरण के लिए:
x * 14 == x * 16 - x * 2 == (x << 4) - (x << 1)
x * 12 == x * 8 + x * 4 == (x << 3) + (x << 2)
एक संख्या को दो की गैर-शक्ति से विभाजित करने के लिए, मुझे किसी भी आसान तरीके के बारे में पता नहीं है, जब तक कि आप कुछ निम्न-स्तरीय तर्क को लागू नहीं करना चाहते हैं, अन्य बाइनरी ऑपरेशन का उपयोग करें और कुछ प्रकार के पुनरावृत्ति का उपयोग करें।
मैंने पायथन कोड का सी। में अनुवाद किया। दिए गए उदाहरण में मामूली खराबी थी। यदि लाभांश मान जो सभी 32 बिट्स को लेता है, तो शिफ्ट विफल हो जाएगी। मैंने समस्या के आसपास काम करने के लिए आंतरिक रूप से 64-बिट चर का उपयोग किया:
int No_divide(int nDivisor, int nDividend, int *nRemainder)
{
int nQuotient = 0;
int nPos = -1;
unsigned long long ullDivisor = nDivisor;
unsigned long long ullDividend = nDividend;
while (ullDivisor < ullDividend)
{
ullDivisor <<= 1;
nPos ++;
}
ullDivisor >>= 1;
while (nPos > -1)
{
if (ullDividend >= ullDivisor)
{
nQuotient += (1 << nPos);
ullDividend -= ullDivisor;
}
ullDivisor >>= 1;
nPos -= 1;
}
*nRemainder = (int) ullDividend;
return nQuotient;
}
ullDivisor >>= 1
से पहले क्यों करते हैं while
? भी, nPos >= 0
चाल नहीं चलेगा ?
विभक्तों को विभाजित करने के लिए एक प्रक्रिया जो पाली और एडिशन का उपयोग करती है, दशमलव प्राथमिक खंड से सीधे फैशन में प्राप्त की जा सकती है जैसा कि प्राथमिक विद्यालय में पढ़ाया जाता है। प्रत्येक भागफल अंक का चयन सरल है, क्योंकि अंक या तो 0 और 1 है: यदि वर्तमान शेष भाग भाजक से अधिक या बराबर है, तो आंशिक भागफल का न्यूनतम महत्वपूर्ण बिट 1 है।
दशमलव लॉन्गहैंड डिवीजन के साथ ही, लाभांश के अंकों को सबसे महत्वपूर्ण से कम से कम महत्वपूर्ण माना जाता है, एक समय में एक अंक। यह बाइनरी डिविजन में आसानी से लेफ्ट शिफ्ट द्वारा पूरा किया जाता है। इसके अलावा, भागफल को वर्तमान भाग के बिट्स को एक स्थान पर स्थानांतरित करके बाईं ओर इकट्ठा किया जाता है, फिर नए भागफल बिट को जोड़ दिया जाता है।
एक शास्त्रीय व्यवस्था में, इन दो बाएं पारियों को एक रजिस्टर जोड़ी के बाएं स्थानांतरण में जोड़ा जाता है। ऊपरी आधा वर्तमान शेष रखता है, निचला आधा प्रारंभिक लाभांश रखता है। जैसा कि लाभांश बिट्स को बाएं रजिस्टर द्वारा शेष रजिस्टर में स्थानांतरित किया जाता है, निचले आधे के अप्रयुक्त कम से कम महत्वपूर्ण बिट्स का उपयोग भागफल बिट्स को संचित करने के लिए किया जाता है।
नीचे x86 असेंबली भाषा और इस एल्गोरिदम का सी कार्यान्वयन है। शिफ्ट और ऐड डिवीजन के इस विशेष संस्करण को कभी-कभी "नो-परफॉर्मिंग" वेरिएंट के रूप में संदर्भित किया जाता है, क्योंकि वर्तमान शेष से विभाजक का घटाव तब तक नहीं किया जाता है जब तक कि शेष भाजक से अधिक या उसके बराबर नहीं होता है। सी में, असेंबली संस्करण द्वारा उपयोग किए गए कैरी फ्लैग की कोई धारणा नहीं है, जो कि पेयर जोड़ी लेफ्ट शिफ्ट में है। इसके बजाय, यह अनुकरण किया गया है, इस अवलोकन के आधार पर कि एक अतिरिक्त modulo 2 n का परिणाम छोटा हो सकता है जो या तो केवल जोड़-तोड़ करता है, अगर कोई बाहर था।
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#define USE_ASM 0
#if USE_ASM
uint32_t bitwise_division (uint32_t dividend, uint32_t divisor)
{
uint32_t quot;
__asm {
mov eax, [dividend];// quot = dividend
mov ecx, [divisor]; // divisor
mov edx, 32; // bits_left
mov ebx, 0; // rem
$div_loop:
add eax, eax; // (rem:quot) << 1
adc ebx, ebx; // ...
cmp ebx, ecx; // rem >= divisor ?
jb $quot_bit_is_0; // if (rem < divisor)
$quot_bit_is_1: //
sub ebx, ecx; // rem = rem - divisor
add eax, 1; // quot++
$quot_bit_is_0:
dec edx; // bits_left--
jnz $div_loop; // while (bits_left)
mov [quot], eax; // quot
}
return quot;
}
#else
uint32_t bitwise_division (uint32_t dividend, uint32_t divisor)
{
uint32_t quot, rem, t;
int bits_left = CHAR_BIT * sizeof (uint32_t);
quot = dividend;
rem = 0;
do {
// (rem:quot) << 1
t = quot;
quot = quot + quot;
rem = rem + rem + (quot < t);
if (rem >= divisor) {
rem = rem - divisor;
quot = quot + 1;
}
bits_left--;
} while (bits_left);
return quot;
}
#endif
दो नंबर लें, 9 और 10 बताएं, उन्हें बाइनरी - 1001 और 1010 लिखें।
परिणाम के साथ शुरू, 0 का आर,।
संख्याओं में से एक को लें, इस मामले में 1010, हम इसे A कहेंगे, और इसे एक बिट से दाईं ओर शिफ्ट करेंगे, यदि आप एक को शिफ्ट करते हैं, तो पहले नंबर को जोड़ दें, हम इसे B कहेंगे, R को।
अब B को एक बिट द्वारा छोड़ दिया गया और तब तक दोहराएं जब तक कि सभी बिट्स A से बाहर शिफ्ट न हो जाएं।
यह देखना आसान है कि क्या हो रहा है यदि आप इसे बाहर लिखते हैं, तो यह उदाहरण है:
0
0000 0
10010 1
000000 0
1001000 1
------
1011010
यहां से ले गए ।
यह केवल विभाजन के लिए है:
int add(int a, int b) {
int partialSum, carry;
do {
partialSum = a ^ b;
carry = (a & b) << 1;
a = partialSum;
b = carry;
} while (carry != 0);
return partialSum;
}
int subtract(int a, int b) {
return add(a, add(~b, 1));
}
int division(int dividend, int divisor) {
boolean negative = false;
if ((dividend & (1 << 31)) == (1 << 31)) { // Check for signed bit
negative = !negative;
dividend = add(~dividend, 1); // Negation
}
if ((divisor & (1 << 31)) == (1 << 31)) {
negative = !negative;
divisor = add(~divisor, 1); // Negation
}
int quotient = 0;
long r;
for (int i = 30; i >= 0; i = subtract(i, 1)) {
r = (divisor << i);
// Left shift divisor until it's smaller than dividend
if (r < Integer.MAX_VALUE && r >= 0) { // Avoid cases where comparison between long and int doesn't make sense
if (r <= dividend) {
quotient |= (1 << i);
dividend = subtract(dividend, (int) r);
}
}
}
if (negative) {
quotient = add(~quotient, 1);
}
return quotient;
}
यह मूल रूप से बेस पावर 2 के साथ गुणा और विभाजित है
पारी बाईं ओर = x * 2 ^ y
शिफ्ट राइट = x / 2 ^ y
shl eax, 2 = 2 * 2 ^ 2 = 8
shr eax, 3 = 2/2 ^ 3 = 1/4
eax
भिन्नात्मक मूल्य नहीं रख सकते 1/4
। (जब तक कि आप पूर्णांक के बजाय निश्चित बिंदु का उपयोग नहीं कर रहे हैं, लेकिन आपने यह निर्दिष्ट नहीं किया है)
यह गुणा के लिए काम करना चाहिए:
.data
.text
.globl main
main:
# $4 * $5 = $2
addi $4, $0, 0x9
addi $5, $0, 0x6
add $2, $0, $0 # initialize product to zero
Loop:
beq $5, $0, Exit # if multiplier is 0,terminate loop
andi $3, $5, 1 # mask out the 0th bit in multiplier
beq $3, $0, Shift # if the bit is 0, skip add
addu $2, $2, $4 # add (shifted) multiplicand to product
Shift:
sll $4, $4, 1 # shift up the multiplicand 1 bit
srl $5, $5, 1 # shift down the multiplier 1 bit
j Loop # go for next
Exit: #
EXIT:
li $v0,10
syscall
नीचे दी गई विधि दोनों संख्याओं को सकारात्मक मानते हुए बाइनरी डिवाइड का कार्यान्वयन है। यदि घटाव एक चिंता का विषय है तो हम बाइनरी ऑपरेटरों का उपयोग करके इसे लागू कर सकते हैं।
-(int)binaryDivide:(int)numerator with:(int)denominator
{
if (numerator == 0 || denominator == 1) {
return numerator;
}
if (denominator == 0) {
#ifdef DEBUG
NSAssert(denominator==0, @"denominator should be greater then 0");
#endif
return INFINITY;
}
// if (numerator <0) {
// numerator = abs(numerator);
// }
int maxBitDenom = [self getMaxBit:denominator];
int maxBitNumerator = [self getMaxBit:numerator];
int msbNumber = [self getMSB:maxBitDenom ofNumber:numerator];
int qoutient = 0;
int subResult = 0;
int remainingBits = maxBitNumerator-maxBitDenom;
if (msbNumber >= denominator) {
qoutient |=1;
subResult = msbNumber - denominator;
}
else {
subResult = msbNumber;
}
while (remainingBits > 0) {
int msbBit = (numerator & (1 << (remainingBits-1)))>0?1:0;
subResult = (subResult << 1) | msbBit;
if(subResult >= denominator) {
subResult = subResult - denominator;
qoutient= (qoutient << 1) | 1;
}
else{
qoutient = qoutient << 1;
}
remainingBits--;
}
return qoutient;
}
-(int)getMaxBit:(int)inputNumber
{
int maxBit = 0;
BOOL isMaxBitSet = NO;
for (int i=0; i<sizeof(inputNumber)*8; i++) {
if (inputNumber & (1<<i)) {
maxBit = i;
isMaxBitSet=YES;
}
}
if (isMaxBitSet) {
maxBit+=1;
}
return maxBit;
}
-(int)getMSB:(int)bits ofNumber:(int)number
{
int numbeMaxBit = [self getMaxBit:number];
return number >> (numbeMaxBit - bits);
}
गुणन के लिए:
-(int)multiplyNumber:(int)num1 withNumber:(int)num2
{
int mulResult = 0;
int ithBit;
BOOL isNegativeSign = (num1<0 && num2>0) || (num1>0 && num2<0);
num1 = abs(num1);
num2 = abs(num2);
for (int i=0; i<sizeof(num2)*8; i++)
{
ithBit = num2 & (1<<i);
if (ithBit>0) {
mulResult += (num1 << i);
}
}
if (isNegativeSign) {
mulResult = ((~mulResult)+1);
}
return mulResult;
}
-(int)multiplyNumber:(int)num1 withNumber:(int)num2
?
16-बिट x86 समाधान में रुचि रखने वाले किसी व्यक्ति के लिए, यहां 1 जेसन नाइट द्वारा कोड का एक टुकड़ा है (वह एक हस्ताक्षरित गुणा टुकड़ा भी शामिल है, जिसे मैंने परीक्षण नहीं किया है)। हालाँकि, उस कोड में बड़े इनपुट्स के मुद्दे हैं, जहां "बीएक्स, बीएक्स" भाग अतिप्रवाह होगा।
निश्चित संस्करण:
softwareMultiply:
; INPUT CX,BX
; OUTPUT DX:AX - 32 bits
; CLOBBERS BX,CX,DI
xor ax,ax ; cheap way to zero a reg
mov dx,ax ; 1 clock faster than xor
mov di,cx
or di,bx ; cheap way to test for zero on both regs
jz @done
mov di,ax ; DI used for reg,reg adc
@loop:
shr cx,1 ; divide by two, bottom bit moved to carry flag
jnc @skipAddToResult
add ax,bx
adc dx,di ; reg,reg is faster than reg,imm16
@skipAddToResult:
add bx,bx ; faster than shift or mul
adc di,di
or cx,cx ; fast zero check
jnz @loop
@done:
ret
या जीसीसी इनलाइन विधानसभा में समान:
asm("mov $0,%%ax\n\t"
"mov $0,%%dx\n\t"
"mov %%cx,%%di\n\t"
"or %%bx,%%di\n\t"
"jz done\n\t"
"mov %%ax,%%di\n\t"
"loop:\n\t"
"shr $1,%%cx\n\t"
"jnc skipAddToResult\n\t"
"add %%bx,%%ax\n\t"
"adc %%di,%%dx\n\t"
"skipAddToResult:\n\t"
"add %%bx,%%bx\n\t"
"adc %%di,%%di\n\t"
"or %%cx,%%cx\n\t"
"jnz loop\n\t"
"done:\n\t"
: "=d" (dx), "=a" (ax)
: "b" (bx), "c" (cx)
: "ecx", "edi"
);
इसे इस्तेमाल करे। https://gist.github.com/swguru/5219592
import sys
# implement divide operation without using built-in divide operator
def divAndMod_slow(y,x, debug=0):
r = 0
while y >= x:
r += 1
y -= x
return r,y
# implement divide operation without using built-in divide operator
def divAndMod(y,x, debug=0):
## find the highest position of positive bit of the ratio
pos = -1
while y >= x:
pos += 1
x <<= 1
x >>= 1
if debug: print "y=%d, x=%d, pos=%d" % (y,x,pos)
if pos == -1:
return 0, y
r = 0
while pos >= 0:
if y >= x:
r += (1 << pos)
y -= x
if debug: print "y=%d, x=%d, r=%d, pos=%d" % (y,x,r,pos)
x >>= 1
pos -= 1
return r, y
if __name__ =="__main__":
if len(sys.argv) == 3:
y = int(sys.argv[1])
x = int(sys.argv[2])
else:
y = 313271356
x = 7
print "=== Slow Version ...."
res = divAndMod_slow( y, x)
print "%d = %d * %d + %d" % (y, x, res[0], res[1])
print "=== Fast Version ...."
res = divAndMod( y, x, debug=1)
print "%d = %d * %d + %d" % (y, x, res[0], res[1])