Scientific notation in MATLAB - matlab

Say I have an array that contains the following elements:
1.0e+14 *
1.3325 1.6485 2.0402 1.0485 1.2027 2.0615 1.7432 1.9709 1.4807 0.9012
Now, is there a way to grab 1.0e+14 * (base and exponent) individually?
If I do arr(10), then this will return 9.0120e+13 instead of 0.9012e+14.
Assuming the question is to grab any elements in the array with coefficient less than one. Is there a way to obtain 1.0e+14, so that I could just do arr(i) < 1.0e+14?

I assume you want string output.
Let a denote the input numeric array. You can do it this way, if you don't mind using evalc (a variant of eval, which is considered bad practice):
s = evalc('disp(a)');
s = regexp(s, '[\de+-\.]+', 'match');
This produces a cell array with the desired strings.
Example:
>> a = [1.2e-5 3.4e-6]
a =
1.0e-04 *
0.1200 0.0340
>> s = evalc('disp(a)');
>> s = regexp(s, '[\de+-\.]+', 'match')
s =
'1.0e-04' '0.1200' '0.0340'

Here is the original answer from Alain.
Basic math can tell you that:
floor(log10(N))
The log base 10 of a number tells you approximately how many digits before the decimal are in that number.
For instance, 99987123459823754 is 9.998E+016
log10(99987123459823754) is 16.9999441, the floor of which is 16 - which can basically tell you "the exponent in scientific notation is 16, very close to being 17".
Now you have the exponent of the scientific notation. This should allow you to get to whatever your goal is ;-).
And depending on what you want to do with your exponent and the number, you could also define your own method. An example is described in this thread.

Related

convert number string into float with specific precision (without getting rounding errors)

I have a vector of cells (say, size of 50x1, called tokens) , each of which is a struct with properties x,f1,f2 which are strings representing numbers. for example, tokens{15} gives:
x: "-1.4343429"
f1: "15.7947111"
f2: "-5.8196158"
and I am trying to put those numbers into 3 vectors (each is also 50x1) whose type is float. So I create 3 vectors:
x = zeros(50,1,'single');
f1 = zeros(50,1,'single');
f2 = zeros(50,1,'single');
and that works fine (why wouldn't it?). But then when I try to populate those vectors: (L is a for loop index)
x(L)=tokens{L}.x;
.. also for the other 2
I get :
The following error occurred converting from string to single:
Conversion to single from string is not possible.
Which I can understand; implicit conversion doesn't work for single. It does work if x, f1 and f2 are of type 50x1 double.
The reason I am doing it with floats is because the data I get is from a C program which writes the some floats into a file to be read by matlab. If I try to convert the values into doubles in the C program I get rounding errors...
So, (after what I hope is a good question,) how might I be able to get the numbers in those strings, at the right precision? (all the strings have the same number of decimal places: 7).
The MCVE:
filedata = fopen('fname1.txt','rt');
%fname1.txt is created by a C program. I am quite sure that the problem isn't there.
scanned = textscan(filedata,'%s','Delimiter','\n');
raw = scanned{1};
stringValues = strings(50,1);
for K=1:length(raw)
stringValues(K)=raw{K};
end
clear K %purely for convenience
regex = 'x=(?<x>[\-\.0-9]*),f1=(?<f1>[\-\.0-9]*),f2=(?<f2>[\-\.0-9]*)';
tokens = regexp(stringValues,regex,'names');
x = zeros(50,1,'single');
f1 = zeros(50,1,'single');
f2 = zeros(50,1,'single');
for L=1:length(tokens)
x(L)=tokens{L}.x;
f1(L)=tokens{L}.f1;
f2(L)=tokens{L}.f2;
end
Use function str2double before assigning into yours arrays (and then cast it to single if you want). Strings (char arrays) must be explicitely converted to numbers before using them as numbers.

Convert number in scientific notation to string in Matlab

I would like to convert a scientific number to a string in Matlab but using a rather specific format. I started with the following:
>> num2str(1E4, '%e')
ans =
'1.000000e+04'
Then played around with the formatstring to get rid of the digits after the decimal point in the first part
>> num2str(1E4, '%.0e')
ans =
'1e+04'
The thing is I want it exactly how I am expressing it in numbers, namely I want a string like this '1E4'. I could use strrep to get rid of that plus sign but I refuse to use it to get rid of the leading 0 on the +04 part since I have other instances of the variable which have things like +10. It it feasible to reproduce the number as a string without resorting to some big complicated algorithm? Preferably using the formatstring?
Solution
According to num2str documentation, you need to use a format parameter of and precision parameter as follows:
num2str(1E4,'%.E')
Result
ans = 1E+04
Read about sprintf . LEt A be your number, to achieve what you want, you can use:
sprintf('%1.0e',A)
Here is a way to convert integers to scientific notation:
function out= scientific(num)
E = 0;
if mod(num,10) == 0
[f n]=factor(num);
E=min(n(ismember(f,[2 5])));
end
out = sprintf('%dE%d',num/10^E,E);
end
>> scientific(134)
ans = 134E0
>> scientific(134000)
ans = 134E3
Another solution that accepts input as vector:
function out= scientific2(num)
E = sum(cumsum(num2str(num(:))-48,2,'reverse')==0,2);
out = num2str([num(:)./10.^E,E],'%dE%d\n');
end
You could use a combination of sprintf and regexprep.
my_format = #(x)regexprep(sprintf('%.E',x),'E\+0*','E');
Examples:
>> my_format(1E4)
ans =
1E4
>> my_format(2E12)
ans =
2E12
This is not ideal for all cases:
>> my_format(5) % Expect 5E0
ans =
5E
>> my_format(1E-4) % Expect 1E-4
ans =
1E-04
We can fix the first case with a token:
f2 = #(x)regexprep(sprintf('%.E',x),'E\+0*(\d)','E$1');
>> {f2(1E4), f2(1E20), f2(5)}
ans =
'1E4' '1E20' '5E0'
And we can fix the second case with tokens and a ? quantifier:
>> f3 = #(x)regexprep(sprintf('%.E',x),'E\+?(-?)0*(\d)','E$1$2');
>> {f3(1E4), f3(1E20), f3(5),f3(1E-1),f3(2E-12)}
ans =
'1E4' '1E20' '5E0' '1E-1' '2E-12'
To explain, sprintf('%.E',x) formats x in scientific notation with E, e.g. 1E+04, then it finds
'E\+?(-?)0*(\d)'
E The literal E
\+?(-?) Either a + or a -; if - then save to group $1
0* As many 0s as it can match, subject to...
(\d) At least one digit, saves digit to group $2
Finally, the matched text is replaced with E$1$2, that is the literal E, then group $1 (a minus sign if found E-, nothing if found E+) and the group $2 (a single digit).

Matlab ShortEng number format via sprintf() and fprintf()?

I like using MATLAB's shortEng notation in the interactive Command Window:
>> a = 123e-12;
>> disp(a);
1.2300e-10 % Scientific notation. Urgh!
>> format shortEng;
>> disp(a);
123.0000e-012 % Engineering notation! :-D
But I want to use fprintf:
>> format shortEng;
>> fprintf('%0.3e', a);
1.2300e-10 % Scientific. Urgh!
How do I print values with fprintf or sprintf with Engineering formatting using the MATLAB Format Operators?
I know I could write my own function to format the values into strings, but I'm looking for something already built into MATLAB.
NOTE: "Engineering" notation differs from "Scientific" in that the exponent is always a multiple of 3.
>> fprintf('%0.3e', a); % This is Scientific notation.
1.230000e-10
There is no way to use directly fprintf format specifier for the format you require. A way around is to use the output of disp as a string to be printed. But disp doesn't return a string, it writes directly to the standard output. So, how to do this?
Here's where evalc (eval with capture of output) comes to the rescue:
%// Create helper function
sdisp = #(x) strtrim(evalc(sprintf('disp(%g)', x)));
%// Test helper function
format ShortEng;
a = 123e-12;
fprintf(1, 'Test: %s', sdisp(a));
This is a workaround, of course, and can backfire in multiple ways because of the untested inputs of the helper functions. But it illustrates a point, and is one of the rare occasions where the reviled eval function family is actually irreplaceable.
You can use the following utility:
http://www.people.fas.harvard.edu/~arcrock/lib118/numutil/unpacknum.m
This will unpack the number also according to a given number N and makes sure that the exponent will be a multiple of N. By putting N=3 you have the Engineering Notation.
More into detail, unpacknum takes 3 arguments: the number x, the base (10 if you want Engineering Notation) and the value N (3 if you want Engineering Notation) and it returns the couple (f,e) which you can use in fprintf().
Check the unpacknum help for a quick example.
This function converts a value into a string in engineering notation:
function sNum = engn(value)
exp= floor(log10(abs(value)));
if ( (exp < 3) && (exp >=0) )
exp = 0; % Display without exponent
else
while (mod(exp, 3))
exp= exp - 1;
end
end
frac=value/(10^exp); % Adjust fraction to exponent
if (exp == 0)
sNum = sprintf('%+8.5G', frac);
else
sNum = sprintf('%+8.5GE%+.2d', frac, exp);
end
end
You can finetune the format to your liking. Usage in combination with fprintf is easy enough:
fprintf('%s\t%s\n', engn(543210.123), engn(-0.0000567)) % +543.21E+03 -56.7E-06
fprintf('%s\t%s\n', engn(-321.123), engn(876543210)) % -321.12 +876.54E+06
You can use the following utility posted to the MATLAB file exchange:
num2eng
It offers extensive control over the formatting of the output string and full input checking, so is more flexible and less prone to error than the simpler evalc approach suggested by user2271770.
It can also output strings using SI prefixes instead of engineering notation, if you prefer.

How do I concatenate the empty String to the beginning of a String in Matlab

Say I typed x = 'BODD' into the command prompt of MATLAB and then said x(1) it would return B. What I want is x(1) to return the empty String ('') or nothing etc. and x(2) to return B and so forth up until x(5) returning the final D?
I assume that you mean that you really do want the empty zero-length string, ''. There have been some Answers to this question that assume that you meant that you wanted the one-character string that contains a space, ASCII value 32.
If that's the case, I'm afraid you can't to that - MATLAB arrays (including character arrays, which is all that a MATLAB "string" is) don't work that way. There are two ways to look at it...
You asked for x(1). Now, the indexing expression that you used, 1, has size 1x1. Therefore, you are guaranteed to get either a 1x1 return value, OR an error. That means that there's no way to get a 0x1 or 0x0 (the true "empty string"). This is similar to the way that, if you had asked for x(2:4), you would be guaranteed to get a 1x3 array of characters back. In that case, 2:4 is a 1x3 array.
There's no way to "meaningfully" prepend a zero-length string to the beginning of another string. If a = 'WXYZ';, then running b = ['' a] just returns 'WXYZ' back. It didn't somehow stick a magical placeholder for an empty string at the front of the original string.
You can't concatenate '' at end or beginning
However, you can have blank/space, like this :-
>> x=BODD;
>> x=[' ' x]; % Use normal matrix concatenation
>> x(1)
ans =
>> x(2)
ans =
B
Try following concatenation
x = [' ' x];
If you want the string itself to still be 'BODD', you could try writing a custom function:
function [char] = emptyConcat(string, index)
if (index == 1)
char = '';
else
char = string(index - 1);

format a number as I want

I have the number: a = 3.860575156847749e+003; and I would show it in a normal manner. So I write b = sprintf('%0.1f' a);. If I print b I will get: 3860.6. This is perfect. Matter of fact, while a is a double type, b has been converted in char.
What can I do to proper format that number and still have a number as final result?
Best regards
Well, you have to distinguish between both the numerical value (the number stored in your computer's memory) and its decimal representation (the string/char array you see on your screen). You can't really impose a format on a number: a number has a value which can be represented as a string in different ways (e.g. 1234 = 1.234e3 = 12.34e2 = 0.1234e4 = ...).
If you want to store a number with less precision, you can use round, floor, ceil to calculate a number which has less precision than the original number.
E.g. if you have a = 3.860575156847749e+003 and you want a number that only has 5 significant digits, you can do so by using round:
a = 3.860575156847749e+003;
p = 0.1; % absolute precision you want
b = p .* round(a./p)
This will yield a variable b = 3.8606e3 which can be represented in different ways, but should contain zeros (in practice: very small values are sometimes unavoidable) after the fifth digit. I think that is what you actually want, but remember that for a computer this number is equal to 3.86060000 as well (it is just another string representation of the same value), so I want to stress again that the decimal representation is not set by rounding the number but by (implicitly) calling a function that converts the double to a string, which happens either by sprintf, disp or possibly some other functions.
Result of sprintf y a text variable. have you tried to declare a variable as integer (for example) and use this as return value for sprintf instruction?
This can be useful to you: http://blogs.mathworks.com/loren/2006/12/27/displaying-numbers-in-matlab/