MATLAB Answers

Troubles with data types: integers, doubles, scientific notation, and type casting

11 views (last 30 days)
Hannah D
Hannah D on 29 Apr 2020
Commented: James Tursa on 1 May 2020
I have a vector of integer elements, and most/all elements are in the thousands. When I look at the vector, some numbers are display in the normal format (eg, 5037) but some are displayed in scienfitic notation (eg 4.2890e+03). When I call the isinteger() function on my variable, it returns false. I think it is probably due to the way that some elements are stored in scientific notation, but I havent found any way, looking online, to force the variable to save all elements in the normal format. If I call isinteger(round()) on my variable, it still returns false. I also cannot typecast my vector to be eg. int16 (which I will get to in a minute).
The reason I need integer values is that some of these values will be used to index an array. I am using the "S = sparse(i,j,v,m,n,nz)" function, and the values m,n,nz all come from my variable. If I try to run it as is, where all of the values are actually integers but Matlab does not recognize them as such, I get the error message
Every one of the elements should be integers, but it throws me an error regardless. Just so you can see what my variables are,
n = numel(x);
idx = 1:n;
x is my integer-valued double vector, and k is a particular element from x.
The documentation for sparse indicates that it shouldn't be problematic, as it says the first two terms (i,j aka idx, x) can be "Data Types: single | double | int8 | int16 | int32 | int64 | uint8 | uint16 | uint32 | uint64 | logical", the third term (v aka 1) can be "Data Types: double | logical", the fourth and fifth terms (m,n aka n,k) can be "Data Types: double" and the last term (nz aka n) can be "Data Types: double"
Based on the documentation, I don't understand why it won't accept my values -- it claims the type "double" is supported for every single input term.
If I try casting my vector, x, to be something else, like an int16, I get the error
even though the documentation claims that it accepts "single | double | int8 | int16 | int32 | int64 | uint8 | uint16 | uint32 | uint64 | logical"
How can I resolve this? Is there any way to force all of the elements in my vector to be saved in the normal format and not scientific notation? Why do I get an error about input types when the documentation claims that data type is supported?

  3 Comments

Stephen Cobeldick
Stephen Cobeldick on 30 Apr 2020
"When I call the isinteger() function on my variable, it returns false. I think it is probably due to the way that some elements are stored in scientific notation..."
No, you are confusing integer types with integer classes. As its documentation for isinteger states, it "...returns logical 1 (true) if A is an array of integer type.", but your array is NOT integer type, your array has type double and so will always return false, regardless of the values it contains (i.e. even if they are all integer values). Nowhere in the isinteger documentation does it suggest that isinteger will check the values of floating point arrays.
The basic data types are introduced here:
"...where all of the values are actually integers..."
That error message clearly tells us that they aren't all integer valued. Based on the start of your question "When I look at the vector, some numbers are display in the normal format (eg, 5037) but some are displayed in scienfitic notation ..." apparently your checking method was simply to look at values displayed in the Command Window or in the Variable Editor/Viewer. Simply looking at how data is displayed is not a robust way to check if it is integer valued or not, nor is it even a particularly reliable method to know the "exact" floating point value (search this forum for "binary floating point" to know more). How data are displayed and how data are stored in memory are two very different things and should not be mixed up.
A robust test like this would let you know how many non-integer-valued elements your array idx has:
>> idx = [0,eps(0),1,1+eps(1)];
>> nnz(mod((idx(:)),1))
ans = 2
"Is there any way to force all of the elements in my vector to be saved in the normal format and not scientific notation?"
Numeric data classes do NOT store any formatting information whatsoever, how the data happens to be displayed at a particular moment by one particular widget is an attribute of that widget and not an attribute of the data class.
How data is displayed is not the same things as how data is stored in computer memory. Do not confuse the two.
Hannah D
Hannah D on 30 Apr 2020
Perhaps I should have been clearer; I suspect that the values displayed in scientific notation are the ones with more floating-point error that makes Matlab think they're not actually integer valued.
And I did your more thorough check for integer values, and even though the documentation claims to be able to support double type inputs for all inputs, I get errors where its asking for integers.
Yes, I can see that one value in one of the input arrays has enough floating point error that it thinks its not an integer, but I don't know why Matlab has a problem with this because 1) the documentation claims to be able to support double type, 2) it still doesn't work if i call round() on the value before feeding it in, and 3) this code has worked before, many times over, when my arrays had values in the 100s, but now the values are in the 1000s and only now do I begin to get errors. I did not change anything in the function except the order of magnitude of the inputs. It had all the same data types, steps, functions, size of arrays, everything.
James Tursa
James Tursa on 30 Apr 2020
I am asking again, please show us a complete small example that demonstrates the problem, not just code snippets. And not pictures of code ... post your code as text and format it with the CODE button.

Sign in to comment.

Accepted Answer

Guillaume
Guillaume on 30 Apr 2020
Edited: Guillaume on 30 Apr 2020
left = 100*round(left,2);
In theory, this should indeed give you integers. Unfortunately, with floating points (double), this is not always going to work and you will get non-integers values. See for example:
>> x = 1.127;
>> y = round(x, 2) %appears to be 1.13. It is not!
y =
1.13
>> z = 100*y %appears to be 113. It is not!
z =
113
>> z - 113 %it is off by a tiny amount
ans =
-1.4210854715202e-14
Even though, mathematically, the below is the same, it is much safer:
left = round(left * 100); %do the multiplication before rounding, then round to nearest integer
The reason is that there are many numbers with just two decimals, such as 1.13, that cannot be stored as double. So instead of storing 1.13 matlab stores the nearest possible number (about 1.12999999999999989342...) which of course when multiplied by 100 is not exactly 113 but 112.99999999999998579... (note the change in the latter digits).
Note that this is not dependent on the version of matlab, and actually applies to any code that uses double representation, not just matlab.

  0 Comments

Sign in to comment.

More Answers (3)

James Tursa
James Tursa on 29 Apr 2020
Edited: James Tursa on 29 Apr 2020
You are confusing integer "types" with integer "values". Integer types are int8, uint8, ... int16, uint64. Integer values a 1, 2, 3, etc. You can store integer "values" in floating point types (single or double) or in integer types (int8, uint16, etc.).
You are also confusing the stored value with the displayed value. A stored integer value can display as an integer format or can display as a floating point format. But how it is displayed on your screen does not affect the underlying storage value. The display format depends on the value and your display settings.
For your particular problem, you need to provide us with a specific example of where you think you are feeding the sparse( ) function proper inputs (show them to us) and then copy & paste the entire error message for us to see. If sparse( ) is complaining that your index arrays are not integer values, then they aren't. And the data values for a sparse matrix need to be either double or logical ... no other sparse matrix data types are supported.
If all of your inputs are type double, and your indexing arrays have only positive integer values, then things should work for you.

  3 Comments

Hannah D
Hannah D on 29 Apr 2020
I am aware that there is a difference, hence why I said "integer-valued double vector", but either way, the documentation claims that it supports double type and integer types.
I did provide both the inputs that I gave to "sparse" and the error it returned, which was a short error message.
I did double-check every value fed in to the "sparse" function, and they're all integer valued. In the first example error, all of them are type "double" but integer valued, and the second example error, they are all integer valued and type double except for the one that is cast to int16. I get similar errors (int16 isn't supported) if I try to cast any of the values to integers
James Tursa
James Tursa on 30 Apr 2020
"... I did provide both the inputs ..."
No. There is a difference between describing your inputs and actually providing your inputs. You need to show us complete code that creates the inputs and calls sparse( ) so we can run it and diagnose things on our own. It may very well be that the documentation is incomplete or incorrect as you say, but we would like to see the code that demonstrates it.
Hannah D
Hannah D on 30 Apr 2020
left = (4+4*rand(2578,1075)).*randn(2578,1075) + (rand(2578,1075)-0.5);
left = 100*round(left,2); % bin and scale
left = left - min(min(min(min(left))))+1; % shift to be integer values
x = left(1,:);
y = left(2,:);
n = numel(x);
x = reshape(x,1,n);
y = reshape(y,1,n);
l = min(min(x),min(y));
x = x-l+1;
y = y-l+1;
k = max(max(x),max(y));
idx = 1:n;
Mx = sparse(idx,x,1,n,k,n);
I have gone and manually checked the values of the variables to confirm that they are integer valued.
What I really don't understand is why the code is giving me errors now because it has worked in the past. I have used it where I had line 2 instead say
left = 10*round(left,1);
and the code ran perfectly, without issue. That was the literal only change, and now I'm getting errors.

Sign in to comment.


Steven Lord
Steven Lord on 30 Apr 2020
Which release of MATLAB are you using? The ability to specify the subscripts (the first two inputs) in the sparse function as arrays of an integer type was added in release R2020a.
From the error message you're receiving, you have at least one element in x that is not an integer value. Find the elements that are not an integer value with:
find(x ~= round(x))

  4 Comments

Show 1 older comment
Stephen Cobeldick
Stephen Cobeldick on 30 Apr 2020
"...but even if I call the round() function before feeding them into sparse(), it still gives me errors"
Please save the exact variables that you are inputting to sparse and upload them here by clicking the paperclip button. Do not alter them in any way: just save and upload.
Steven Lord
Steven Lord on 30 Apr 2020
I agree with Stephen Cobeldick. Either upload the exact data you pass into the sparse function or give us a complete code that we can run with which you can reproduce the behavior. You're going to want to set the random number generator to a specific state with rng before calling rand and randn so we can reproduce exactly what you ran.
Guillaume
Guillaume on 30 Apr 2020
Well, it's fairly easy to reproduce the problem with for example just:
left = [1.127 2; 0 0]
I've explained the problem in my answer.

Sign in to comment.


Hannah D
Hannah D on 30 Apr 2020
In the end I got it to work by calling round() basically on everything at multiple different points (which I am still not certain why it wouldn't work if I just called round on the values once?) before passing it into the function

  3 Comments

Guillaume
Guillaume on 30 Apr 2020
I've given you a proper explanation of the problem and a much better solution that calling round after each point.
Hannah D
Hannah D on 30 Apr 2020
@Guillaume I meant, I have tried calling round() on the variable after its creation, not just the round(left,2) in the declaration, and that still didn't fix the issue. I had to call round() on multiple things in order to get it to work
James Tursa
James Tursa on 1 May 2020
@Hannah: I do not mean to be harsh, but this sounds like you don't really understand your problem and you have put a bandaid on it. If you understood the problem and what the floating point calculations are doing, you would be able to create better code as Guillaume has suggested and avoid sprinkling round( ) all over your code until things seem to work ... this time. It would be better if you took the time to understand why you are getting the problems at each step and then write better code to avoid those problems in the first place.

Sign in to comment.