I'm trying to get a string from a double like this:
double aDouble;
NSString* doubleString = [NSString stringWithFormat:#"%g", aDouble];
With most numbers I get the desired results, but for
10000.03
I get:
10000
as my string. Is there a way to prevent this behavior? I would like a result a string of
10000.03
%g can be tricky in the absence of a precision specifier. Note that %f can be used with double values, and you can limit the number of digits after the decimal point by using %.2f (replace 2 with whichever number of digits you want).
%g is a format specifier that chooses between %f or %e according to the following algorithm:
If a non-zero precision has been specified, let P be that precision
If a zero precision has been specified, let P be 1
If a precision hasn’t been specified, let P be 6
Let X be the exponent if the conversion were to use the %e format specifier
If P > X >= -4, the conversion is with style %f and precision P - (X + 1)
Otherwise, the conversion is with style %e and precision P - 1.
Unless the # flag is used, any trailing zeros are removed from the fractional portion of the result, and the decimal point character is removed if there is no fractional portion remaining.
In your case, %g doesn’t specify a precision, hence P = 6. When converting 10000.03 with %e, which gives 1.000003e+04, the exponent is 4, hence X = 4. Since P > X >= -4, the conversion is with style %f and precision P - (X + 1) = 6 - (4 + 1) = 1. But 10000.03 with precision 1 (one digit after the decimal point) yields 10000.0, which has no actual fractional portion, hence %g formats 10000.03 as 10000.
Try %.2f instead of %g
floats and double are base two representations of number that we like to see in base ten, just as there is no way to exactly represent the number 1/3 in base ten with a finite number of digits there are many base 10 number which can not be exactly represented in base 2. For example 0.1 (1/10) can not be represented exactly in base 2.
Related
I want to convert 64 bit numbers from binary to decimal. Since dec2bin only supports up to 52 bits, I thought I could roll my own function and use uint64 to go beyond this limit:
function [dec] = my_bin2dec(bin)
v = uint64(length(bin)-1:-1:0);
base = uint64(2).^v;
dec = uint64(sum(uint64(base.*(uint64(bin-'0')))));
end
However, it does not work as expected:
my_bin2dec('111000000000000000000000000000000000001010110101011101000001110')
ans =
8070450532270651392
my_bin2dec('111000000000000000000000000000000000001010110101011101000001111')
ans =
8070450532270651392
Whereas this is the correct result:
(111000000000000000000000000000000000001010110101011101000001110)bin
= (8070450532270651918)dec
(111000000000000000000000000000000000001010110101011101000001111)bin
= (8070450532270651919)dec
What am I missing? It seems like there is some operation still performed using 52bit double arithmetic, but I don't know which one.
I checked if the operations are available for uint64 and it seems that the ones I use (power, times, sum) are there:
>> methods uint64
Methods for class uint64:
abs bitxor diff isinf mod plus sum
accumarray bsxfun display isnan mpower power times
all ceil eq issorted mrdivide prod transpose
and colon find ldivide mtimes rdivide tril
any conj fix le ne real triu
bitand ctranspose floor linsolve nnz rem uminus
bitcmp cummax full lt nonzeros reshape uplus
bitget cummin ge max not round xor
bitor cumprod gt min nzmax sign
bitset cumsum imag minus or sort
bitshift diag isfinite mldivide permute sortrowsc
You were right in saying that
It seems like there is some operation still performed using 52bit double arithmetic.
The problem is in line
dec = uint64(sum(uint64(base.*(uint64(bin-'0')))));
The operation sum(uint64(base.*(uint64(bin-'0')))) gives a double result, which only has about 15 significant digits. That's why your lowest digits are wrong. Subsequent conversion into uint64 doesn't help, because precision has already been lost.
The solution is to sum natively in uint64. This gives a uint64 result with its full precision:
dec = sum(uint64(base.*(uint64(bin-'0'))), 'native');
Had the same thought as #beaker, break it into chunks:
%% dec2bin
x=intmax('uint64')
MSBs = dec2bin( bitshift(x,-32) ,32)
LSBs = dec2bin( bitand(x, hex2dec('FFFFFFFF')) ,32)
y = [MSBs LSBs]
%% bin2dec
MSBs = y(1:32)
LSBs = y(33:64)
z = bitor( bitshift( uint64(bin2dec(MSBs)) , 32 ) , uint64(bin2dec(LSBs)) )
% (now x = z)
Oddly enough, it seems that dec2bin doesn't give an error, but does give incorrect answers for 64 bit numbers:
dec2bin( intmax('uint64') )
ans =
10000000000000000000000000000000000000000000000000000000000000000
How can one find the last two digits of a decimal number using MATLAB?
Example:
59 for 1.23000659
35 for 56368.35
12 for 548695412
There will always be issues when you have a decimal number with many integer digits and fractional digits. In this case, the number of integer and decimal digits decide if we are correct or not in estimating the last two digits. Let's take at the code and the comments thereafter.
Code
%// num is the input decimal number
t1 = num2str(num,'%1.15e') %// Convert number to exponential notation
t1 = t1(1:strfind(t1,'e')-1)
lastind = find(t1-'0',1,'last')
out = str2num(t1(lastind-1:lastind)) %// desired output
Results and Conclusions
For num = 1.23000659, it prints the output as 59, which is correct thanks
to the fact that the number of integer and decimal digits don't add upto
more than 16.
For num = 56368.35, we get output as 35, which is correct again and the
reason is the same as before.
For num = 548695412, we are getting the correct output of 12 because of the
same good reason.
For an out of the question sample of num = 2736232.3927327329236576
(deliberately chosen a number with many integer and fractional digits),
the code run gives output as 33 which is wrong and the reason could be
inferred from the fact that integer and decimal digits add upto a much
bigger number than the code could handle.
One can look into MATLAB command vpa for getting more precision, if extreme cases like the 4th one are to dealt with.
Convert to string and then extract the last two characters:
x = 1.23; % x = 1.23
s = num2str(x); % s = "1.23"
t = s(end-1:end); % t = "23"
u = str2num(t); % u = 23
Note: depending on your specific needs you might want to supply a precision or formatSpec to num2str.
The other two answers are nice and straight forward, but here you have a mathematical way of doing it ;)
Assuming a as your number,
ashift=0.01*a; %shift the last two digits
afloor=floor(ashift); %crop the last two digits
LastDecimals=a-100*afloor; %substract the cropped number form the original, only the last two digits left.
Of course if you have non-natural numbers, you can figure those out too with the same "floor and subtract technique as above.
I wish to utilize som sort of combination of %f and %g in my fprintf. I wish to remove trailing zeros and use 6 decimal points if there are 6 decimals that are non zero. %g removes zeros but here precision does not affect the number of decimal points. What to do?
So if this is the behaviour you want:
0.123456789 -> 0.123457 (rounded up at the 6th decimal place)
999.123456789 -> 999.123457 (six decimal places, regardless of the number of significant figures)
1.123000000 -> 1.123 (remove trailing zeros)
then you can use %f:
fprintf('%.6f', number);
You can use %.<n>g, where n defines maximal number of digits to be used.
>> fprintf('%.6g\n', 4087.145678);
4087.15
>> fprintf('%.6g\n', 45.2);
45.2
how to filter out float values with only zeroes beyond decimal & others having some non-zero values beyond decimal too.
for example.
13.000000
13.120001
i want it like this:
13.0
13.120001
If your application stores the floating point values in something like C/C++'s float's or double's, you may have a problem here.
First of all, float/double in the majority of cases represents values using base-2 and when you do something like double x = 0.1;, x in fact will never be equal to 0.1, but it will be very close to 0.1. That is because not every decimal (base-10) fraction can be represented exactly in base-2.
When you print or convert that x to a string using one of the printf-like functions, the resultant string can vary from something like 0.099999999 to 0.1 to 0.10000000000000000555. The result will depend on what's in x and on how you convert it to a string (how many digits you allow for the integer part, fractional part or all).
Generally there's no one-size-fits-all solution here. In one case the exactness and rounding issues can be unimportant, while in another they can be the most important. When performance is more important than the exact representation of decimal fractions, you use base-2 types. Otherwise, for example, when you're counting money, you use special types (and you may first need to construct them) that can represent decimal fractions exactly and then you avoid some of the described issues at a cost of extra computation time and maybe storage.
You may sometimes use fixed-point types and arithmetic. For example, if your numbers should not have more than 3 fractional digits and aren't too big, you can use scaled integers:
long x = 123456; // x represents 123.456
You add, subtract and compare them just as regular integers, but you multiply and divide them differently, for example like this:
long x = 123456; // x represents 123.456
long y = 12345; // y represents 12.345
long p = (long)(((long long)x * y) / 1000); // p=1524064, representing x*y=1524.064
long q = (long)((long long)x * 1000) / y); // q=10000, representing x/y=10.000
And in this case it is relatively easy to figure out the digits of the fractional part, just look at (x%1000)/100, (x%100)/10 and x%10.
split 13.00000 or 13.20001 into 2 values like in 13.0000 as 13 and 0000 ...so compare 2nd value whether it is greater than 0 (ex:13.20001 where 2001>0) if its yes then set same value . else (ex 13.0000 where 0000=0) then set %.2f=> 13.00
Why does the select statement below return two different values ?
declare #tempDec decimal
set #tempDec = 1.0 / (1.0 + 1.0)
select #tempDec, 1.0 / (1.0 + 1.0)
That's fine for literals like 1.0, but if you're pulling the data from table columns, you need to cast/convert the first evaluated number in your equation:
convert(decimal, [col1]) / ([col2] + [col3])
-or-
convert(decimal(15, 2), [col1]) / ([col2] + [col3])
I found out from a coworker just as I posted this.
You need to specify the default precision and scale.
This works in this scenario:
declare #tempDec decimal(3,2)
From MSDN:
decimal[ (p[ , s] )] and numeric[ (p[ , s] )]
Fixed precision and scale numbers. When maximum precision is used, valid values are from - 10^38 +1 through 10^38 - 1. The SQL-92 synonyms for decimal are dec and dec(p, s). numeric is functionally equivalent to decimal.
p (precision)
The maximum total number of decimal digits that can be stored, both to the left and to the right of the decimal point. The precision must be a value from 1 through the maximum precision of 38. The default precision is 18.
s (scale)
The maximum number of decimal digits that can be stored to the right of the decimal point. Scale must be a value from 0 through p. Scale can be specified only if precision is specified. The default scale is 0; therefore, 0 <= s <= p. Maximum storage sizes vary, based on the precision.