Loren on the Art of MATLAB

Double or Nothing? No Joking! 16

Posted by Loren Shure,

Note the date, folks. I am using this excuse to be a bit light-hearted today. I saw the following quote on someone's door here at MathWorks.

MATLAB gives you the benefit of the double.

This made me smile and I realized that there are some ways in which MATLAB uses doubles that might not always be obvious to users.

Contents

What Type is X?

X = 17
X =
    17

When the value of X is displayed, as 17, there is no decimal point or other indication that X is not strictly an integer. Despite that, X is a double precision variable. I have at least a couple of ways to find this information programmatically.

whos
  Name      Size            Bytes  Class     Attributes

  X         1x1                 8  double              

class(X)
ans =
double

By default, MATLAB variables are double precision arrays. In the olden days, these were the only kind of arrays in MATLAB. Back then even character arrays were stored as double values.

Other Integers

There are other ways to store integers in MATLAB these days. Let me list a few:

  • characters: char
  • signed integers, e.g., int8
  • unsigned integers, e.g., uint8

Display the Values Stored in Various Types

First I'll convert the double to a string and display it.

str17 = num2str(X)
str17 =
17

Notice that the display looks different than that for X. There is no leading white space for character arrays (unless it's part of the string itself).

Now let's look at the display for some integer types.

u8 = uint8(X)
i8 = int8(X)
u8 =
   17
i8 =
   17

Notice here that you can't distinguish the type based on the display of the values. The default numeric display in MATLAB tries to display the maximum amount of information compactly.

Some Behaviors

Because the default type is double, we have found it really convenient to allow some interaction between double scalar values and other numeric array types. The way I like to state the behavior is that, for arithmetic operators, MATLAB does the calculations as if the arrays are doubles, and then respects the memory savings of the non-double storage class. What this means, for example, is that I can take a grayscale image and halve the values like so, causing the new image to be darker.

p = imread('pout.tif');
class(p)
imshow(p)
ans =
uint8
pHalf = p * 0.5;
class(pHalf)
imshow(pHalf)
ans =
uint8

MATLAB Types

Have you had cases where you either took advantage of the interactions of integers and doubles in MATLAB, or where integers and floating point integers gave you a surprise? Let me know here.


Get the MATLAB code

Published with MATLAB® 7.10

16 CommentsOldest to Newest

I’m glad to learn of ‘class()'; it will be useful compared to several ‘isdouble()’, ‘ischar()’ etc.
I also was pleased to find ‘typecast()’ recently, when having to convert text and binary data to a single stream of bytes for an instrument. These, and other functions in the ‘see also’ parts of their help pages, are very handy for anyone who has to use non-doubles.

The behaviour you’ve described for operations with double and smaller types is most surprising, particularly to users at all familiar with C (if they haven’t thoroughly read the help page for ‘uintN’ e.g. ‘uint8′).

a = double(100)
b = uint8(30)
c = double(0)
c = a*b

That ‘c’ should end up equal to 255 is a real surprise on the first time.

I can understand truncating if assigning a larger number into a variable that is already a smaller type, but not this immediate truncation just because one operand is a small type. All the debugging that’s gone into people’s first programs that use small ints in matlab!
Too late now to change the behaviour, of course…

I have always been puzzled about how Matlab can figure out how to do the right thing when using the == operator with doubles. In C this is a very dangerous thing to do but it seems to work OK with Matlab. I do worry that I will get sloppy and this will get me in trouble at the worst possible time. Code like this seems inherently dangerous and makes it even more difficult to port Matlab to other languages:

>> x = 1.2

x =

    1.2000

>> 2*x == 2.4

ans =

     1

>> 

Loren,

I too am surprised that operating on an integer and a double yields an integer after the calculation was done in double. Why was that selecion made rather than making the result of the operation yield the type of the operand with highest precedence (is that the correct word?)?

Also, I see in the doc that

“you can combine a scalar or array of an integer data type with a scalar, but not an array, of type double “

and

“you cannot combine an array of an integer data type with either of the following:

A scalar or array of a different integer data type

A scalar or array of type single”

At first glance, I don’t understand why Matlab has these restrictions. Why are only scalar doubles allowed in mixed operations?

Paul-

Doubles were singled out since they are the default data type for assignment, e.g., x = 3. The scalar rule was simply VERY convenient for lots of code we looked at, and we didn’t want arrays to blow up in size by going from some integer type to double. And if you already had a double array and were combining it with an integer array, you were already committed to having at least some arrays (not scalars) in double. We were worried that it would trip people up, especially those coming from C. We have had surprisingly little negative feedback for the actual behavior, but definitely have heard a surprised reaction from those who use(d) lower level languages – but not much from people who started their computing in MATLAB.

–Loren

Bob-

Be very careful with == and doubles unless you KNOW they are integers stored in floating point. Otherwise, you will likely be surprised that some values you compare are not equal, because, for example, one was generated from using :, like 0:0.001:1 – not all the values in that sequence can be exactly represented in floating point, so if you compare them using == with 0.007, 0.008, etc., not all of them will return true. Sometimes you do get “lucky” though.

–Loren

@Bob,

Examples abound to show that == can be dangerous in MATLAB.

(.42 – .5 + .08)==0 % False
(.3-.2)==.1 % False

Also, just hang around the NewsGroup long enough and you will be sure to see this item reported as a bug in MATLAB.

Loren,

We employ integer types to good effect in our codes. We often work with large arrays and the memory savings derived from going to various integer types as index arrays are often considerable.

In our experience integer types work mostly seamlessly and do the right thing. Our greatest impediment to using integers, however, is that the SPARSE function does not accept integer index vectors ‘i’ and ‘j’ in its SPARSE(i,j,s) syntax. At least not up to and including R2009b. This frequently leads to statements of the form

   S = sparse(double(i), double(j), s, m, n)

I know the reason is historical and that we can achieve the desired effect using

   S = accumarray([i, j], s, [m, n], [], [], true)

but it still seems inelegant somehow.

Oh, and a final matter: Users must sometimes be keenly aware of the overflow behaviour of their chosen integer types. For instance,

   uint8(255) + 1 == uint8(255)

This (documented) behaviour tripped us up one time when we were implementing refinement in a finite element code.

Other than that, I’m a very happy integer user.

- Bård Skaflestad

Bård,

Thanks for the info. It would help greatly if you would request an enhancement to sparse (use the support link at the right). It counts more coming from you than from me. Thanks.

–Loren

Loren,

Thank you for your suggestion. I have submitted an enhancement request for the feature of using *intN-typed index arrays to sparse.

- Bård Skaflestad

I have been puzzled by the maximum size of uint64 being limited to that of double. I have mentioned this to some of my MATLAB-enabled collegues who rarely believe me :-)

I tried to use uint64 as an efficient means of bit-manipulating huffman codes. When data is stored as bytes but logically is a “sea of bits”, it is very difficult to find a compact, efficient way of decoding that data (in any language I believe).

Having large uints and doing bitshifts/bitmasking would have been neat in that case. I ended up with a less efficient array of logicals and 8x the memory consumption.

Knut-

Are you aware of the function typecast? It might help you pack things into uint64 and do manipulations that you want (though you might find not all the functions are available on uint64 that you would like to use). We’re aware of the “missing” functionality in uint64. Perhaps you can put in an enhancement request with *specific functionality* you are looking for for uint64s. See the support link to the right.

Thanks.
–Loren

Ideally, what I would like is something like:

chunk_64_bits = zeros(1,1,'uint64');
next_length = 8;
while remaining_file
    chunk_64_bits = read_next_8_bytes(fname);
    remaining_bits = 64;
    while remaining_bits > 0
        %recursive bit-decoding part
        current_bits   = bitand(chunk_64_bits, (2^next_length)-1);
        next_length    = magic_function(current_bits);
        %updating buffer for next iteration
        chunk_64_bits  = bitshift(chunk_64_bits, next_length);
        remaining_bits = remaining_bits - next_length;
    end
end

The details really do not matter, I may have stumbled on some of the shift directions for this example. What matters is that I want to continously read some bytes into a large unsigned integer, do bitshifts on that integer to recurssively find out what the next bitshift will be, then reload the large integer with new bytes when I get to its end. uint64 being limited to “uint52″ means that the method is less efficient (I would love having uint128 mapping directly to efficient SSE instructions).

The coarse outline of my work-around is:

remaining_bits = 8*filesize;
binary_vector = zeros(remaining_bits,1,'logical');
binary_vector = read_bytes_bin_vec(fname);
next_length = 8;
cur_pos = 1;
while remaining_bits > 0
    %recursive bit-decoding part
    current_bit_vec   = binary_vector(cur_pos+[0:next_length-1]);
    current_bits = 0;
    for bit_idx = 1:next_length
        current_bits = current_bits + current_bit_vec(bit_idx)*2^bit_idx;
    end
    next_length    = magic_function_bin(current_bits);
    %updating buffer for next iteration
    cur_pos = cur_pos + next_length;
    remaining_bits = remaining_bits - next_length;
end

This may be a prime example of what MATLAB is really not ment for, and where mex files should be used, but wheres the challenge in that? :-)

I’m glad to hear that “We’re aware of the ‘missing’ functionality in uint64.”
I’m not sure why the word missing is in quotes. Am I ‘missing’ something here?

I suppose you are aware that Matlab’s int32 is also ‘missing’ some ‘functionality’.

Here is an example of how slow Matlab’s int32 arithmetic can be:

function p = ShuffleP3264(n,wbits);
% This shows the difference between Matlab’s
% normal 64-bit double ‘integers’ and 32-bit int32 ‘integers’.
%
% Generate a random permutation vector p(1:n) using
% Knuth’s Algorithm P, Section 3.4.2, TAOCP, Vol 2, 2nd Ed.
% Derek O’Connor, 30 Mar 2010

if wbits == 32    % This type propagates below and
   n = int32(n);  % causes a big slowdown
end;

p = 1:n;          % Identity permutation.

for i = n:-1:2
   r = floor(rand*i)+1; % random integer between 1 and i
   t = p(r);
   p(r) = p(i);         % Swap(p(r),p(i))
   p(i) = t;
end;

return; % ShuffleP3264

% TEST
% clear all
% tic;p = ShuffleP3264(10^7,64);toc
% Elapsed time is 2.005458 seconds.
%
% clear all
% tic;p = ShuffleP3264(10^7,32);toc
% Elapsed time is 24.762971 seconds.

On this problem int32 arithmetic is 12 times slower than the default ‘double integers’. This means that I can have really huge int32 arrays but I can’t do anything with them.

My enhancement request: (1) Provide proper integer types (16 to 64), signed, unsigned, and (2) IEEE floating point type: single, double. I use the word ‘type’ to indicate storage format and arithmetic on this format.

R2020a, perhaps?

Derek O’Connor.

Matlab 7.6.0.324 (R2008a) 64 bit
Dell Precision 690, Intel 2xQuad-Core E5345 @ 2.33GHz
16GB RAM, Windows7 64-bit Professional.

Derek-

Please make a full enhancement request using the support link on the right of the blog page, including as much information about what problems you are trying to solve that the enhancements would support. Your request will have more potency than if I make it for you. Thanks.

–Loren

Thanks for coming to OSU. When are you coming back? Alyssa is ready…

Have you looked at using Process Explorer to have a more fine-tuned view on memory use? It’s available free from MS, just google ‘process explorer’. Much better than task manager for deep info about process internals.

Also, there was a question about matlab reporting duplicate function names. At one time I had a user pushing java, and for some reason I have yet to suss out, he wrote a cd.m. I don’t know exactly when it happens, but it seems when I use java functions at the command line I get warned about this existing duplicate. So, maybe it’s the jre that does this and not matlab per se.

John-

Thanks for the process explorer info. I have recently added it to my machine. For most of what I want to show, I don’t need *that* much detail, but it is good to have.

Not sure about the cd wrt java. You might want to contact support about that. I have never seen that myself.

–Loren

These postings are the author's and don't necessarily represent the opinions of MathWorks.