Gnu Octave, Round a Number to Units Precision

GNU Octave, round a number to units precision

How to round off elements in a matrix in Octave:

There are many different ways to round a matrix and round a number in octave.

Option 1, use of sprintf format feature

mymatrix=[100.1234567, 2.12345; 3.1234567891, 4.1234];
rows = rows(mymatrix);
cols = columns(mymatrix);
for i = 1:rows
for j = 1:cols
sprintf("%5.2f", mymatrix(j,i))
endfor
endfor

Output, note the "%5.2f" token. The 'f' means expect a float, the 5 means occupy 5 spaces. The 2 means 2 units precision after the decimal point.

ans = 100.12
ans = 3.12
ans = 2.12
ans = 4.12

Option 2, round to significant digits using eval and mat2str

mymatrix2=[100.1234567, 2.12345; 3.1234567891, 4.1234];
j = mat2str(mymatrix2, 3);
mymatrix2=eval(j)

Output, matrix rounded to 3 significant digits, notice 100.123 rounded to 100 while the 2.12345 was rounded to 2.12

mymatrix2 = 100.0000     2.1200
3.1200 4.1200

Option 3, use the round function

The round function does not have a precision parameter in Octave. However you can hack around it by multiplying each item in the matrix by 100, rounding it to the nearest int, then dividing each item by 100:

mymatrix=[100.1234567, 2.12345; 3.1234567891, 4.1234];
round(mymatrix .* 100) ./ 100

Output, round occurs correctly:

ans = 100.1200     2.1200
3.1200 4.1200

Option 4, specify a output_precision(num)

You noticed that option 3 above kept the trailing zeros, which may be undesirable, so you can tell them to go away by setting output_precision:

mymatrix=[100.1234567, 2.12345; 3.1234567891, 4.1234];
disp(mymatrix);
output_precision(3)
disp(mymatrix)

Output:

100.1235     2.1235
3.1235 4.1234

100.123 2.123
3.123 4.123

Octave has some odd behavior when trying to do rounding because octave tries hard to uniformly apply a uniform rounding to all items in a matrix. So if you have multiple columns with wildly different values, octave sees a tiny value and says: "I should convert that to an exponential like 1.0e-04, and so the same exponential is applied to the entire data structure in the matrix.

Octave prints everything

Put a semicolon after a statement to suppress output from that statement. This doesn't suppress explicit output (from the disp function), so you can just put a semicolon after every line in your function.

Octave and MATLAB share syntax, so you can use the MATLAB symbol reference (http://www.mathworks.com/help/matlab/matlab_prog/symbol-reference.html) to learn more about the special symbols in MATLAB, including the semicolon.

Formatting Decimal places in R

Background: Some answers suggested on this page (e.g., signif, options(digits=...)) do not guarantee that a certain number of decimals are displayed for an arbitrary number. I presume this is a design feature in R whereby good scientific practice involves showing a certain number of digits based on principles of "significant figures". However, in many domains (e.g., APA style, business reports) formatting requirements dictate that a certain number of decimal places are displayed. This is often done for consistency and standardisation purposes rather than being concerned with significant figures.

Solution:

The following code shows exactly two decimal places for the number x.

format(round(x, 2), nsmall = 2)

For example:

format(round(1.20, 2), nsmall = 2)
# [1] "1.20"
format(round(1, 2), nsmall = 2)
# [1] "1.00"
format(round(1.1234, 2), nsmall = 2)
# [1] "1.12"

A more general function is as follows where x is the number and k is the number of decimals to show. trimws removes any leading white space which can be useful if you have a vector of numbers.

specify_decimal <- function(x, k) trimws(format(round(x, k), nsmall=k))

E.g.,

specify_decimal(1234, 5)
# [1] "1234.00000"
specify_decimal(0.1234, 5)
# [1] "0.12340"

Discussion of alternatives:

The formatC answers and sprintf answers work fairly well. But they will show negative zeros in some cases which may be unwanted. I.e.,

formatC(c(-0.001), digits = 2, format = "f")
# [1] "-0.00"
sprintf(-0.001, fmt = '%#.2f')
# [1] "-0.00"

One possible workaround to this is as follows:

formatC(as.numeric(as.character(round(-.001, 2))), digits = 2, format = "f")
# [1] "0.00"

How do I do floating point rounding with a bias (always round up or down)?

I think the best way to achieve this is to rely on the fact that according to the IEEE 754 floating point standard, the integer representation of floating point bits are lexicographically ordered as a 2-complement integer.

I.e. you could simply add one ulp (units in the last place) to get the next floating point representation (which will always be slightly larger than your treshold if it was smaller, since the round error is at most 1/2 ulp)

e.g.

 float floatValue = 7.f/10;
std::cout << std::setprecision(20) << floatValue << std::endl;
int asInt = *(int*)&floatValue;
asInt += 1;
floatValue = *(float*)&asInt;
std::cout << floatValue << std::endl;

prints (on my system)

 0.69999998807907104492
0.70000004768371582031

To know when you need to add one ulp, you'll have to rely on the difference of floor and a rounded floor

 if (std::floor(floatValue * 100.) != std::floor(floatValue * 100. + 0.5)) {
int asInt = *(int*)&floatValue;
asInt += 1;
floatValue = *(float*)&asInt;
}

Would correctly convert 0.69.. to 0.70.. but leave 0.80.. alone.

Note that the float gets promoted to a double via the multiplication with 100. before the floor is applied.

If you don't do this you risk getting in the situation that for

 7.f/10.f * 100.f

The (limited in precision) float representation would be 70.00...

How to make rounded percentages add up to 100%

Since none of the answers here seem to solve it properly, here's my semi-obfuscated version using underscorejs:

function foo(l, target) {
var off = target - _.reduce(l, function(acc, x) { return acc + Math.round(x) }, 0);
return _.chain(l).
sortBy(function(x) { return Math.round(x) - x }).
map(function(x, i) { return Math.round(x) + (off > i) - (i >= (l.length + off)) }).
value();
}

foo([13.626332, 47.989636, 9.596008, 28.788024], 100) // => [48, 29, 14, 9]
foo([16.666, 16.666, 16.666, 16.666, 16.666, 16.666], 100) // => [17, 17, 17, 17, 16, 16]
foo([33.333, 33.333, 33.333], 100) // => [34, 33, 33]
foo([33.3, 33.3, 33.3, 0.1], 100) // => [34, 33, 33, 0]


Related Topics



Leave a reply



Submit