How can I check if a register is evenly divisible by 7? - math

I want to check if the value of the register ax is divisible by 7, with remainder = 0. How can I do it?

You can use the same way as shown in this answer, with different constants of course.
The modular multiplicative inverse of 7 mod 216 is 0x6db7, which (by definition) means that numbers of the form x = n * 7 will obey x * 0x6db7 = n, where n will be less than or equal to 0xffff / 7. So if you get something bigger out of x * 0x6db7, you know it's not a multiple of 7. Also, non-multiples of 7 cannot also map to low results, because multiplication by an odd number modulo a power of two is bijective.
So you can use (not tested)
imul ax, ax, 0x6db7
cmp ax, 0x2492
ja not_multiple_of_7
This is for unsigned numbers of course.
As a bonus, ax will be the original value divided by 7 iff it was a multiple of 7.

org 100h
mov ax,14
mov cl,7
div cl
cmp ah,0
je positive
PRINTN "The number has a remainder"
jmp finish
positive:
PRINTN "The number has no remainder"
finish:
PRINTN "After comparison"
mov ah, 0
int 16h
ret

Related

Intel 8086 Division. Need AX to be denominator not numerator

Need to divide CL by 10. I understand that in division AX will always be the numerator, but I need it to be the denominator.
In the code below I attempt to move the value I need as the numerator into AL and then put 10 into CL and divide.
Any help would be appreciated.
Mov Al, Cl
Mov Cl, 10
Div Cl
Need to divide Cl by 10
So you'll want the quotient back in the CL register then.
Your corrected solution (10 bytes):
mov al, cl
xor ah, ah ;Clear high byte because DIV will use the entire AX
mov cl, 10
div cl ;Divides AX by 10, leaves quotient in AL
mov cl,al
Shorter solution (6 bytes):
mov al, cl
aam ;Divides AL by 10, leaves quotient in AH
mov cl, ah
On 8086 the AAM instruction exclusively divides by 10.
On x86 the AAM instruction can divide by any byte-sized number.
So this AAM instruction is in effect an 8 bit by 8 bit division!
Is there a way then to divide a register by 10?
All divisions implicitly use the accumulator (AL, AX, DX:AX). Just copy your register to the accumulator first.

Largest positive number in register

In assembly we can obtain negative numbers by substracting the positive one from FFFFh and then increasing it by one, so about half of registers is reserved for negative numbers.
And if we multiply two numbers, and the result is too large for one register, the rest is passed to dx.
So, my question is, what is the largest positive number, that can be stored in the register, because when I'm multiplying different pairs of numbers, neither ax nor dx is the same.
You can interpret the same register contents either as signed number, or as unsigned number. In the first case max value is 0x7F*** = 2^(regsize-1)-1 (32767 for 16 bit), in the second case max value is 0xFF** = 2^regsize-1 (65535 for 16 bit)
(Note that there are imul and mul commands for multiplication, the first accounts for signs).
Hex byte example
80 imul 2 = FF:00
80 mul 2 = 01:00

8086 assembly language unsigned interpretation

I have to write a program in 8086 assembly that calculates this:
(a+b*c+2/c)/(2+a)+e
where
a,b - byte
c - word
e - doubleword,
in unsigned interpretation.
So far I have this:
assume cs:code,ds:data
data segment
a db 4
b db 2
c dw 16
e dd 126
data ends
code segment
start:
mov ax,data
mov ds,ax
and here is my program
mov al,b ; al=b
mov ah,0 ; ax=b;
mul c; dx:ax=b*c; b*c=doubleword
mov bx,ax; we save b*c in bx to use ax in the division 2/c
mov al,2; al=2
mov ah,0; al=ax=0
div c; ax=dx:ax/c ; dx=dx:ax%c;
I don't know how to continue.
When you write
mov bx,ax; we save b*c in bx to use ax in the division 2/c
you're actually only saving the low word of the product between B and C. It works with the numbers provided but it's not a general solution.
In stead of writing
mov al,2; al=2
mov ah,0; al=ax=0
use mov ax,2 and remember to explicitely clear the DX register because the division needs it.
To continue I would suggest you create a result variable of doubleword size because in the end the size of your largest expression participant defines the size of the result. Then on the way move or add your partial results to this variable.
If you are allowed to use 32 bit registers a suitable approach might be to promote all values to 32 bit and continue from there.

Arithmetic operations in ASM Language

I just need some help. I don't fully understand and I am fairly new to masm32 so if you could explain, that would be great!
MOV AX, 200
ADD AX, 300
MOV RESULT, AX
Will result be equal to 500? I tried adding 3 and 2 and using this to show output:
MOV DX, RESULT
ADD RESULT, '0'
MOV AH, 02H
INT 21H
But the output is a candy cane character! Where is it wrong?
Now I assume subtraction will work the same as addition, so on to Multiplication we go.
This is what I did for multiplication
MOV AX, 30
MOV BX, 8
MUL BX
MOV RESULT, AX
Is RESULT's value equal to 240?....
I tried AX as 3 and BX as 2. The output is a spade. Can you point me to the right direction?
Now division.
MOV AX, 30
MOV BX, 12
DIV BX
MOV RESULT, AX
What holds the quotient? If what I read was correct, that would be AX, and DX holds the remainder...?
I have already done 8 bit arithmetic (using AL, BL, DL...) and I tried to apply it here, sadly, when the RESULT becomes greater than 128, it just outputs garbage. Someone suggested that I should declare my variables as 'RESULT dw ?' instead of 'RESULT db ?' and instead of AL BL registers I should use AX BX.... Now I'm stuck.
Any help would be appreciated! Sorry if these questions seem too trivial. Anyway, thanks in advance! :DD
MOV AX, 200
ADD AX, 300
MOV RESULT, AX
Will result be equal to 500?
Yes.
I tried adding 3 and 2 and using this to show output:
MOV DX, RESULT
ADD RESULT, '0'
MOV AH, 02H
INT 21H
But the output is a candy cane character! Where is it wrong?
You're adding '0' to RESULT after moving RESULT to DX. You should probably add '0' to DL instead of to RESULT.
Now division.
MOV AX, 30
MOV BX, 12
DIV BX
MOV RESULT, AX
What holds the quotient? If what I read was correct, that would be AX, and DX holds the remainder...?
DIV BX divides the 32-bit value DX:AX by BX, so you should clear DX before the division. The quotient will end up in AX and the remainder in DX.
Someone suggested that I should declare my variables as RESULT dw ?
If you're going to move 16-bit values to/from the variable (e.g. MOV RESULT,AX) then you should make the variable (at least) 16 bits.

Rounding to the nearest integer in floating point

How can I round a floating point number to the nearest integer? I am looking for the algorithm in terms of binary since I have to implement the code in assembly.
UPDATED with method for proper rounding to even.
Basic Algorithm:
Store the 23-exponent+1'th bit (after the decimal point). Next, zero out the (23-exponent) least significant bits. Then use the stored bit and the new LSB to round. If the stored bit bit is 1, add one to the LSB of the non-truncated part and normalize if necessary. If the stored bit is 0, do nothing.
**
For results matching IEEE-754 standard:
**
Before Zeroing out the (23-exponent) least significant bits, OR together the (22-exponent) least significant bits. Call the result of that OR the rounding bit.
The stored (23-exponent + 1) bit (after the decimal point) will be called the guard bit.
Then zero out the (23-exponent) least significant bits).
If the guard bit is zero, do nothing.
If the guard bit is 1, and the sticky bit is 0, add one to the LSB if the LSB is 1.
If the guard bit is 1 and the sticky bit is 1, add one to the LSB.
Here are some examples using the basic algorithm:
x = 62.3
sign exponent mantissa
x = 0 5 (1).11110010011001100110011
Step 1: Store the exponent+1'th bit (after the decimal point)
exponent+1 = 6th bit
savedbit = 0
Step 2: Zero out 23-exponent least significant bits
23-exponent = 18, so we zero out the 18 LSBs
sign exponent mantissa
x = 0 5 (1).11110000000000000000000
Step 3: Use the next bit to round
Since the stored bit is 0, we do nothing, and the floating point number has been rounded to 62.
Another example:
x = 21.9
sign exponent mantissa
x = 0 4 (1).01011110011001100110011
Step 1: Store the exponent+1'th bit (after the decimal point)
exponent+1 = 5th bit
savedbit = 1
Step 2: Zero out 23-exponent least significant bits
23-exponent = 19, so we zero out the 19 LSBs
sign exponent mantissa
x = 0 4 (1).01010000000000000000000
Step 3: Use the next bit to round
Since the stored bit is 1, we add one to the LSB of the truncated part and get 22, which is the correct number:
We start with:
sign exponent mantissa
x = 0 4 (1).01010000000000000000000
Add one at this location:
+ 1
And we get 22:
sign exponent mantissa
x = 0 4 (1).01100000000000000000000
There is an SSE instruction for round to nearest: http://www.musicdsp.org/showone.php?id=246
inline int float2int(float x) {
int i;
__asm {
fld x
fistp i
}
return i;
}
Decrease the exponent by 1, add 1, increase the exponent by 1, truncate. Or just add 0.5 and truncate. Whichever floats your boat.

Resources