Matlab: How to properly get a mask equivalent to 2^63-1? - matlab

I'm having some problems with MATLAB and 64-bit integers. I want to have a mask equivalent to 2^63-1 (all ones except the MSB), but MATLAB just seems to round everything.
>> mask_fraction = uint64(9223372036854775807)
mask_fraction = 9223372036854775808 % This is 2^63 again, not 2^63-1!
Similarly,
>> uint64(2^63)
ans = 9223372036854775808
>> uint64(2^63-1)
ans = 9223372036854775808
Another one of my attempts simply doesn't work:
>> uint64(2^63) - 1
??? Undefined function or method 'minus' for input arguments of type 'uint64'.
Thoughts?

#BasSwinckels correctly points out one issue. I'll address another.
The first non-exactly representable double-precision floating point integer is 2^53+1. When you pass in expressions to the uint64 function they are evaluated as doubles before being cast to uint64. If these expressions evaluate to a double precision integer that is not exactly representable, you'll see behavior like you described. This is exactly why uint64(2^63-1) and uint64(2^63) both return 9223372036854775808. All powers of two can be safely represented in double precision, so uint64(2^63)-1 or uint64(2^63)-uint64(1) are what you should use (once you figure out your other issue).

I don't see the problems you report. On my computer (Matlab R2012b on 64-bit Ubuntu12.04):
>> mask_fraction = uint64(9223372036854775807)
mask_fraction =
9223372036854775807
>> uint64(2^63) - 1
ans =
9223372036854775807
Do you maybe run an older Matlab version?
I also find the 'undefined function or method minus ...' error a bit suspicious. Do you have uint64 aliased to some other function? Try clear uint64 first ...

It seems from the other comments that Matlab does not implement the minus method for class uint64 in some older versions. The ugly workaround below works for me in R2011b:
>> bitset(intmax('uint64'), 64, 0)
ans =
9223372036854775807

I don't know if it is supported by the version of MATLAB you are using but this might help
mask_fraction = uint64(intmax('int64'))
which returns
mask_fraction =
9223372036854775807
2^63-1 is the maximum value for int64.

Related

Why doesn't num2fixpt function return my expected counterpart fixed point value?

I am trying to convert from float/double to fixed point notation, for instance let's use the number x = 0.39 as input.
I would like to convert x into its unsigned 16 bits fixed-point counterpart, to do so in C++ I am accustomed to use the expression xFixedPoint = round(x*2^(16)), this will make that the fixed point version of 0.39 is 25559.
However, I cannot get that result if I make use of num2fixpt function, I am using it in the following way
num2fixpt(0.39, ufix(16))
ans = 0
What am I doing wrong when using num2fixpt function?
>> num2fixpt(0.39,ufix(16),2^-2)
ans =
0.2500
So you also need to scale to get the integer representation, i.e. 2^16*num2fixpt(...)

Matlab data type specification

I have a problem with data type in MATLAB. It's a simple code of converting binary to decimal. For my further task, those should be integer 64 bit. How can I do it?
This code converts those value into double. And, type casting isn't helpful; for example, for the first value, sum is 4.0265e+09 but after casting via Y = typecast(sum, 'int64'); it generates 4750734656922451968 which is not correct value.
example.png:
I = imread('example.png');
level = graythresh(I);
img = im2bw(I,level);
sz=size(img);
for i=1:sz(1)
sum=0;
p=1;
for j=sz(2):-1:1
sum=sum+img(i,j)*p;
p=p*2;
end
disp(sum);
end
You should use cast instead of typecast
>> s = 4.0265e+09;
>> cast(s, 'int64')
ans =
4026500000
typecast converts data without altering the underlying byte values whereas cast converts data and attempts to keep the same value. typecast as you have found can change the value of data as it does not alter the underlying byte values. typecast simply changes the type that MATLAB uses to interpret the underlying byte values.
Alternatively you could simply use int64
>> int64(s)
ans =
4026500000
to convert data whilst attempting to keep the same value.
Aside: sum is a built-in MATLAB function. It is not recommended that you call a variable sum as you will overwrite the built-in MATLAB function.

Square root of type int32 variable

I tried to calculate the square root of a type int32 variable using the sqrt() function, but I got this error: Undefined function 'sqrt' for input arguments of
type 'int32'. Then I found that there's a function called isqrt() that calculates the square root of type integer variables but it doesn't exist in my Matlab version (R2013a). I tried to download this function but I can't find it. I tried powering the value to (1/2) but integers can only be raised to positive integral powers.
So is there any way to do this?
You could write your own isqrt using an anonymous function:
%// variable
A = int32(16)
%// helper function
isqrt = #(x) int32(sqrt(double(x)))
%// root
iroot = isqrt(A)
This function should just used as that, if you're sure that it actually possible to calculate the root, as casting a decimal value to int32(...) will round it, without displaying an error.
So to make it a little more robust, you could create a function like:
function iroot = isqrt(integer)
root = sqrt(double(integer));
if mod(root,1) == 0
iroot = int32( root );
else
disp('Input has no integer root')
end
end
Here is a solution that avoids rounding that happens when you convert from double to an integer type by using fix and also it supports any integer type by using cast and class functions:
isqrt = #(x) cast(fix(sqrt(double(x))), class(x));
So for example:
>> isqrt(int32(15))
ans =
3
However
>> int32(sqrt(double(int32(15))))
ans =
4
Use fix instead of floor to handle negative values correctly:
>> isqrt(int8(-15))
ans =
0 + 3i

Matlab nchoosek got difference answer using int64 and sym

This is a question about the function nchoosek in Matlab.
I want to find nchoosek(54,25), which is the same as 54C25. Since the answer is about 10^15, I originally use int64. However the answer is wrong with respect to the symbolic one.
Input:
nchoosek(int64(54),int64(25))
nchoosek(sym(54),sym(25))
Output:
1683191473897753
1683191473897752
You can see that they differ by one. This is not really an urgent problem since I now use sym. However can someone tell me why this happens?
EDIT:
I am using R2013a.
I take a look at the nchoosek.m, and find that if the input are in int64, the code can be simplified into
function c = nchoosek2(v,k)
n = v; % rename v to be n. the algorithm is more readable this way.
classOut = 'int64';
nd = double(n);
kd = double(k);
nums = (nd-kd+1):nd;
dens = 1:kd;
nums = nums./dens; %%
c = round(prod(nums));
c = cast(c,classOut);
end
However, the outcome of int64(prod(nums./dens)) is different from prod(sym(nums)./sym(dens)) for me. Is this the same for everyone?
I don't have this problem on R2014a:
Numeric
>> n = int64(54);
>> k = int64(25);
>> nchoosek(n,k)
ans =
1683191473897752 % class(ans) == int64
Symbolic
>> nn = sym(n);
>> kk = sym(k);
>> nchoosek(nn,kk)
ans =
1683191473897752 % class(ans) == sym
% N!/((N-K)! K!)
>> factorial(nn) / (factorial(nn-kk) * factorial(kk))
ans =
1683191473897752 % class(ans) == sym
If you check the source code of the function edit nchoosek.m, you'll see it specifically handles the case of 64-bit integers using a separate algorithm. I won't reproduce the code here, but here are the highlights:
function c = nchoosek(v,k)
...
if int64type
% For 64-bit integers, use an algorithm that avoids
% converting to doubles
c = binCoef(n,k,classOut);
else
% Do the computation in doubles.
...
end
....
end
function c = binCoef(n,k,classOut)
% For integers, compute N!/((N-K)! K!) using prime factor cancellations
...
end
In 2013a this can be reproduced...
There is as #Amro shows a special case in nchoosek for classOut of int64 or unit64,
however in 2013a this is only applied when the answer is between
flintmax (with no argument) and
double(intmax(classOut)) + 2*eps(double(intmax(classOut)))
which for int64 gives 9007199254740992 & 9223372036854775808, which the solution does not lie between...
If the solution had fallen between these values it would be recalculated using the subfunction binCoef
for which the help states: For integers, compute N!/((N-K)! M!) using prime factor cancellations
The binCoef function would have produced the right answer for the given int64 inputs
In 2013a with these inputs binCoef is not called
Instead the "default" pascals triangle method is used in which:
Inputs are cast to double
The product of the vector ((n-k+1):n)./(1:k) is taken
this vector contains k double representations of fractions.
So what we have is almost certainly floating point error.
What can be done?
Two options I can see;
Make your own function based on the code in binCoef,
Modify nchoosek and remove && c >= flintmax from line 81
Removing this expression will force Matlab to use the more accurate integer based calculation for inputs of int64 and uint64 for any values within their precision. This will be slightly slower but will avoid floating point errors, which are rightfully unexpected when working with integer types.
Option one - should be fairly straight forward...
Option two - I recommend keeping an unchanged backup of the original function, or makeing a copy of the function with the modification and use that instead.

Matlab dec2bin gives wrong values

I'm using Matlab's dec2bin to convert decimal number to binary string. However, I'm getting wrong results. For example:
>> dec2bin(13339262925365424727)
ans =
1011100100011110100101001111010011000111111100011011000000000000
I checked both in a C++ implementation and in wolfram alpha and the correct result is:
1011100100011110100101001111010011000111111100011011001001010111
Is there any problem with my usage of Matlab's desc2bin?
Thanks,
Gil.
Your code is equivalent to:
x=13339262925365424727;
dec2bin(x)
but if you check the value of x, you will notice that it outruns double precision. The number is simply to large to be stored in a 64bit double. The precision is 2^11, check eps(x)
To deal with large numbers, using vpa from the symbolic toolbox is a good option, is this available?
Here is a solution using vpa:
function l=ldec2bin(x)
if x>2^52
head=floor(x/2^52);
tail=x-head*2^52;
l=[ldec2bin(head),dec2bin(double(tail),52)];
else
l=dec2bin(double(x));
end
end
usage:
>> ldec2bin(vpa('13339262925365424727'))
ans =
1011100100011110100101001111010011000111111100011011001001010111
/Update:
I came across a much shorter implementation of dec2bin for symbolic variables:
>> sdec2bin=#(x)(feval(symengine,'int2text',x,2))
sdec2bin =
#(x)(feval(symengine,'int2text',x,2))
>> sdec2bin(sym('13339262925365424727'))
ans =
1011100100011110100101001111010011000111111100011011001001010111
The integer seems to long, maybe you should try de2bi function;
http://www.mathworks.com/help/comm/ref/de2bi.html
Assuming that the input is less than intmax('uint64'), as in the example, here is a solution that doesn't require the Symbolic Math toolbox. This supports two input arguments, matching dec2bin, is vectorized, and should be much faster:
function s=int2bin(d,n)
%INT2BIN Convert nonnegative integer to a binary string
if isempty(d)
s = '';
return;
end
d = d(:);
if ~isinteger(d) || any(d < 0)
error('int2bin:InvalidIntegerInput',...
'First input must be a nonnegative integer class array.');
end
if nargin < 2
n = 1
else
n = round(double(n));
end
m = double(nextpow2(max(d)));
s = [repmat('0',length(d),n-m) rem(bsxfun(#bitshift,d,1-m:0),2)+'0'];
If you don't mind a bit less performance and prefer a one-line anonymous function, try:
int2bin = #(d,n)char(rem(bsxfun(#bitshift,d(:),1-max(n,double(nextpow2(max(d(:))))):0),2)+'0');
or this one that uses bitand instead of bitshift:
int2bin = #(d,n)char(~~bsxfun(#bitand,d(:),2.^(max(n,nextpow2(max(d(:)))):-1:0))+'0');
All versions above assume that d is a nonnegative integer class variable, e.g., uint64(13339262925365424727), and that n is a nonnegative numeric scalar. You can find full-featured int2bin and bin2int functions on my GitHub.