what is the most significant bit and least significant number - math

what is the most significant bit (MSB) and least significant bit (LSB) for, 0.11001 (binary)
is it MSB => 1 = (2 superscript 0) or 1 = (2 superscript -1)
is it LSB => 1 = (2 superscript -5) or 1 = (2 superscript -4)
what is the right method to calculate MSB and LSB, should it shift on decimal point to left to get the MSB.

Related

Fixed point multiplication in assembly (x86)

I want to multiply and divide an unsigned 8.8 fixed-point number in the
ax register with 1.00125 and store the result in ax as well.
I know that fixed point multiplication/division requires some extra steps
but I have no idea how to implement those in assembly.
Help is greatly appreciated.
If you care about accuracy, 1.00125 can't be stored exactly in any integer format or in any floating point format because it's a recursive fraction in binary (in binary it's 1.000000000101000111101011100001010001111010111...b where that 00001010001111010111 sequence repeats forever). For this reason I'd convert it into the rational number 801/800; and then do x * 1.00125 = (x * 801) / 800 (possibly with "round to nearest" on the division).
If you don't care about accuracy, then the more bits you can use for "1.00125" the closer the result will be to the correct answer. With 8 bits ("1.7 fixed point") the closest you can get is 1.0000000b, which means you can just skip the multiplication (x * 1.00125 = x). With 16 bits ("1.15 fixed point") the closest you can get is 1.000000000101001b (or 1.001220703125 in decimal).
However, you can cheat more. Specifically, you can significantly increase accuracy with the same number of bits by doing (x * 1) + (x * 0.00125). E.g. instead of having a 16 bit constant like 1.000000000101001b (where 9 bits are zeros), you can have a 16-bit constant like 0.0000000001010001111010111b (where the 16 bits are the last 16 bits without any of the leading zeros). In this case the constant is very close (like 0.00124999880) rather than "less close" (like 1.001220703125 was).
Ironically; with only 16 bits, this "0.00125" is more accurate than a 32-bit floating point representation of 1.00125 can be.
So.. in assembly (assuming everything is unsigned) it might look like:
;ax = x << 8 (or x as an 8.8 fixed point number)
mov cx,ax ;cx = x << 8
mov bx,41943 ;bx = 41943 = 0.00124999880 << 25
mul bx ;dx:ax = (x << 8) * (0.00124999880 << 25) = x * 0.00124999880 << 33
;dx = x * 0.00124999880 << 17
shr dx,9 ;dx = x * 0.00124999880 << 17 >> 9 = x * 0.00124999880 << 8, carry flag = last bit shifted out
adc dx,0 ;Round up to nearest (add 1 if last bit shifted out was set)
lea ax,[dx+cx] ;ax = x << 8 + x * 0.00124999880 << 8 = x * 1.00124999880 << 8
Of course the problem here is that converting it back to "8.8 fixed point" ruins most of the accuracy anyway. To keep most of the accuracy, you could use a 32-bit result ("8.24 fixed point") instead. This might look like:
;ax = x << 8 (or x as an 8.8 fixed point number)
mov cx,ax ;cx = x << 8
mov bx,41943 ;bx = 41943 = 0.00124999880 << 25
mul bx ;dx:ax = (x << 8) * (0.00124999880 << 25) = x * 0.00124999880 << 33
add ax,1 << 8 ;To cause the following shift to round to nearest
adc dx,0
shrd ax,dx,9
shr dx,9 ;dx:ax = x * 0.00124999880 << 33 >> 0 = x * 0.00124999880 << 24
;cx:0 = x << 24
add dx,cx ;dx:ax = x << 24 + x * 0.00124999880 << 24 = x * 1.00124999880 << 24
The other problem is that there's potential overflow. E.g. if x was 0xFF.FF (or about 255.996) the result would be something like 256.32 which is too big to fit in an "8.8" or "8.24" or "8.anything" fixed point format. To avoid that problem you can just increase the number of integer bits (and reduce the accuracy by 1 bit) - e.g. make the result "9.7 fixed point", or "9.23 fixed point".
The important points here are:
a) For "fixed point" calculations, every operation (multiplication, division, addition, ...) causes the decimal point to move.
b) Because the decimal point keeps moving, it's best to adopt a standard notation for where the decimal point is at each step. My way is to include an "explicit shift" in the comments (e.g. "x << 8" rather than just "x"). This "explicit shift documented in the comments" makes it easy to determine where the decimal point moves, and if/how much you need to shift left/right to convert to a different fixed point format.
c) For good code, you need to pay attention to accuracy and overflow, and this causes the decimal point to move around even more (and makes the use of a "standard notation for where the decimal point is" more important).
An easy solution is to just use the x87 floating point unit to do the multiplication. Assuming real mode with nasm (untested):
example:
push bp
mov sp, bp ; establish stack frame
push ax
push ax ; make space for quotient
fild word [bp-2] ; load number
fld st0 ; duplicate top of stack
fmul dword [factor] ; compute product
fistp word [bp-2]
fmul dword [invfac] ; compute quotient
fistp word [bp-4]
pop dx ; quotient
pop ax ; product
pop bp ; tear down stack framt
ret
factor dd 1.00125
invfac dd 0.999875 ; 1/1.00125
This leaves the quotient in dx and the product in ax. Rounding is done according to the rounding mode configured in the x87 FPU (which should be rounding to nearest by default).
One thing to understand about fixed point multiplication that the point of rhe result is the point of operand 1 plus the point of operand 2.
Thus, when multiplying two numbers with fixed point of zero, we get a result with fixed point zero.
And when multiplying two numbers with fixed point at 8 places (binary) we get a number with fixed point at 16 places.
So, need to scale down such result as needed.

step function that increases gait with X

I feel like a moron for not seeing how to express this.
I have need of a step function that approximates a linear function, with frequent, small steps near 0 and fewer, larger steps as X grows, approach some nominal max gait.
e.g.
/ |
/ |
/____| +5
/|
/ |
/ |
/ |
/____| +5
/|
/ |
/ |
/ |
/____| +5
/|
/ |
/ |
/___| +4
/|
/ |
/__| +3
/|
/_| +2
/| +1
I assume you want a function whose graph is the horizontal lines in your example.
If you check the graph's corners that lie on the line, you see that the x-coordinates (as well as the y-coordinates) are the triangular numbers 0, 1, 3, 6, 10, 15, ... They are the partial sums of the arithmetic series 0 + 1 + 2 + 3 + 4 + 5 + ...
It is well known that the formula for the nth triangular number is
x = n*(n+1)/2
That is a quadratic equation in n. If we solve that equation for n and take the positive root we get
n = (-1 + sqrt(8*x + 1)) / 2
So given any point on one of your horizontal line segments, we can find which segment it is by taking the integer part (floor) of that expression. We then use our original expression to find the appropriate y value for that segment. Thus our final expression, slightly simplified, is
0.5 * int((-1 + sqrt(8*x + 1))/2) * int((1 + sqrt(8*x + 1))/2)
Note that the above expression is undefined for x < -1/8 and is zero for -1/8 <= x < 0. To avoid those, only graph for x >= 0. That is an expression in one line. In a computer program there are some obvious efficiencies that could be made, such as calculating n = int((-1 + sqrt(8*x + 1))/2) before using the function value 0.5 * n * (n + 1). You could also avoid the negative x values.
Here is the resulting graph (unfortunately leaving in the values for -1/8 <= x < 0), with dashed vertical and diagonal lines added for clarity.

Normalize number between 0 and 1 in user profile

I'm working on user-profile where each term exists in the user-profile have wight and the weight formulated from set of factors such as (duration, total number of visit ...etc) , I need to normalize the result of their summation to be number between 0 and 1, I performed this equation:
(x+y+z+......)/100
Where x, y and z are factors. I have suggested this equation to my self (I'm sorry I'm not very good in math :( ), but unfortunately it returns some value more than 1 , so is there any way that can be applied to limit the result of the summation between 0 and 1?
Many thanks in advance.
Ok, generally, to normalize, this is what you do:
Find the absolute minimum value, and subtract this from your number. (This may be 0, in which case you can skip this step.)
Find the absolute maximum value. Your total range after step 1 will be from 0..(maximum - minimum). Divide your number by this value, and everything will be in the range of 0..1.
To spin it back, you do the opposite: take your normalized number, multiply by the range (i.e. max - min), then add back the min.
The reason you're having a problem is because x + y + z + ... has a range that is not 100.
Example
If x has a range of 0-10, y has a range of 15-25 and z has a range of 10-25, and your specific values are x = 8, y = 17, z = 12:
x + y + z = 8 + 17 + 12 = 37
min = 0 + 15 + 10 = 25
max = 10 + 25 + 25 = 60
so your normalized value is calculated by doing:
(37 - 25) / (60 - 25) = (12 / 35) = 0.342857 (approximately).
To go back from normalized to a composite number, do the opposite:
0.342857 * 35 = 11.999995 = 12 once rounded.
12 + 25 = 37
If your variables are unbounded, nobody can reach the normalized value 1, because if someone achieved 1, another person with larger factors would exceed 1.
This said, you can transform every factor with a function that maps [0 +inf[ to [0 1[, like X/(X+a) or 1-2^(-X/a), where a is some scaling constant (chosen by you). You will apply this transform to the individual factors and average them, or just apply it to the global sum.

Avoiding bias in randomly generated subtraction problems

I'm writing a Python script to generate problems for mental arithmetic drills. The addition and multiplication ones were easy, but I'm running into trouble trying to generate unbiased problems for the subtraction ones.
I want to be able to specify a minimum and maximum value that the minuend (first number) will be -- e.g., for two-digit subtraction it should be between 20 and 99. The subtrahend should also have a range option (11-99, say). The answer needs to be positive and preferably also bounded by a minimum of, say, 10 for this situation.
So:
20 < Minuend < 99
11 < Subtrahend < 99
Answer = Minuend - Subtrahend
Answer >= 10
All the numeric values should be used as variables, of course.
I have these conditions met as follows:
ansMin, ansMax = 10, 99
subtrahendMin, minuendMax = 11,99
# the other max and min did not seem to be necessary here,
# and two ranges was the way I had the program set up
answer = randint(ansMin, ansMax)
subtrahend = randint(subtrahendMin, minuendMax - answer)
minuend = answer + subtrahend # rearranged subtraction equation
The problem here is that the minuend values wind up being nearly all over 50 because the answer and subtrahend were generated first and added together, and only the section of them that were both in the bottom 25% of the range will get the result below 50%. (Edit: that's not strictly true -- for instance, bottom 1% plus bottom 49% would work, and percentages are a bad way of describing it anyway, but I think the idea is clear.)
I also considered trying generating the minuend and subtrahend values both entirely randomly, then throwing out the answer if it didn't match the criteria (namely, that the minuend be greater than the subtrahend by a value at least greater than the answerMin and that they both be within the criteria listed above), but I figured that would result in a similar bias.
I don't care about it being perfectly even, but this is too far off. I'd like the minuend values to be fully random across the allowable range, and the subtrahend values random across the range allowed by the minuends (if I'm thinking about it right, this will be biased in favor of lower ones). I don't think I really care about the distribution of the answers (as long as it's not ridiculously biased). Is there a better way to calculate this?
There are several ways of defining what "not biased" means in this case. I assume that what you are looking for is that every possible subtraction problem from the allowed problem space is chosen with equal probability. Quick and dirty approach:
Pick random x in [x_min, x_max]
Pick random y in [y_min, y_max]
If x - y < answer_min, discard both x and y and start over.
Note the bold part. If you discard only y and keep the x, your problems will have an uniform distribution in x, not in the entire problem space. You need to ensure that for every valid x there is at least one valid y - this is not the case for your original choice of ranges, as we'll see later.
Now the long, proper approach. First we need to find out the actual size of the problem space.
The allowed set of subtrahends is determined by the minuend:
x in [21, 99]
y in [11, x-10]
or using symbolic constants:
x in [x_min, x_max]
y in [y_min, x - answer_min]
We can rewrite that as
x in [21, 99]
y = 11 + a
a in [0, x-21]
or again using symbolic constants
x in [x_min, x_max]
y = y_min + a
a in [0, x - (answer_min + y_min)].
From this, we see that valid problems exist only for x >= (answer_min + y_min), and for a given x there are x - (answer_min + y_min) + 1 possible subtrahents.
Now we assume that x_max does not impose any further constraints, e.g. that answer_min + y_min >= 0:
x in [21, 99], number of problems:
(99 - 21 + 1) * (1 + 78+1) / 2
x in [x_min, x_max], number of problems:
(x_max - x_min + 1) * (1 + x_max - (answer_min + y_min) + 1) / 2
The above is obtained using the formula for the sum of an arithmetic sequence. Therefore, you need to pick a random number in the range [1, 4740]. To transform this number into a subtraction problem, we need to define a mapping between the problem space and the integers. An example mapping is as follows:
1 <=> x = 21, y = 11
2 <=> x = 22, y = 12
3 <=> x = 22, y = 11
4 <=> x = 23, y = 13
5 <=> x = 23, y = 12
6 <=> x = 23, y = 11
and so on. Notice that x jumps by 1 when a triangular number is exceeded. To compute x and y from the random number r, find the lowest triangular number t greater than or equal to r, preferably by searching in a precomputed table; write this number as q*(q+1)/2. Then x = x_min + q-1 and y = y_min + t - r.
Complete program:
import random
x_min, x_max = (21, 99)
y_min = 11
answer_min = 10
triangles = [ (q*(q+1)/2, q) for q in range(1, x_max-x_min+2) ]
upper = (x_max-x_min+1) * (1 + x_max - (answer_min + y_min) + 1) / 2
for i in range(0, 20):
r = 1 + random.randrange(0, upper)
(t, q) = next(a for a in triangles if a[0] >= r)
x = x_min + q - 1
y = y_min + t - r
print "%d - %d = ?" % (x, y)
Note that for a majority of problems (around 75%), x will be above 60. This is correct, because for low values of the minuend there are fewer allowed values of the subtrahend.
I can see a couple of issues with your starting values - if you want the answer to always be greater than 10 - then you need to either increase MinuendMin, or decrease SubtrahendMin because 20-11 is less than 10... Also you have defined the answer min and max as 3,9 - which means the answer will never be more than 10...
Apart from that I managed to get a nice even distribution of values by selecting the minuend value first, then selecting the subtrahend value based on it and the answerMin:
ansMin = 10
minuendMin, minuendMax = 20,99
subtrahendMin = 9;
minuend = randint(minuendMin, minuendMax )
subtrahend = randint(subtrahendMin,(minuend-ansMin) )
answer = minuend - subtrahend
You say you've already got addition working properly. Assuming you have similar restrictions for the addends/sum you could rearrange the factors so that:
minuend <= sum
subtrahend <= first addend
answer <= second addend
A similar mapping can be made for multiplication/division, if required.

Inverse (Column) Row-Major Order Transformation

Can anyone provide/refer to the inverse of the 'indices -> offset'* transformation for Multi-Dimensional Row-Major Order. Also, (pseudo)code would be appreciated.
http://en.wikipedia.org/wiki/Row-major_order
To give an example, an simplification of the particular problem which prompted my question:
I have a 3 dimensional data hierarchy, expressed in the space spanned by (a,b,c) where a, b, and c are integers larger or equal zero and less then N_a, N_b, and N_c. I want to express the data an one dimensional array. The "offset," In Row-Major Order, is then given as follows:
int offset(a, b, c){
return a*N_b*N_c + b*N_c + c;
}
What is then the reverse transformation, i.e.:
int a(int offset);
int b(int offset);
int c(int offset);
Furthermore, how to i generalise this to N'th dimension indexation? The problem which prompted this question is of 5'th dimension.
In case it matters, I am writing in c/c++.
If the index is calculated as
offset = row + column*NUMROWS
then the inverse would be
row = offset % NUMROWS
column = offset / NUMROWS
where % is modulus, and / is integer division.
This assumes the first element is at offset 0, row 0 and column 0. If they start at 1, you would have to add or subtract 1 at appropriate places.
For higher dimensions, you will have to repeat this for every measure.
offset = x + WIDTH*(y + HEIGHT*(z + DEPTH*time));
and the inverse
x = offset % WIDTH
offset = offset / WIDTH
y = offset % HEIGHT
offset = offset / HEIGHT
z = offset % DEPTH
offset = offset / DEPTH
time = offset
You could also extract a specific coordinate:
z = (offset / (WIDTH * HEIGHT)) % DEPTH

Resources