Skip to main content

functions - Permanently rounding numbers/values to a given number of significant figures


I am searching for a simple way of rounding and setting an input to a desired number of significant figures. There are a vast number of posts that discuss similar problems, but none address this issue. I turned to writing my own function. Here it is below:


SigFig[x_, n_] :=
(p := Solve[10^i <= Abs[x] < 10^(i + 1), i, Integers][[1, 1, 2]];
N[Round[x, 10^(p - n + 1)], n]) // Quiet

SigFig rounds any real number x (of magnitude greater than or equal to 1) to a specified number of significant figures n.



Obviously the biggest flaw in this function is not catering for numbers of magnitude less than 1, and thus also the problem of preceeding insignifcant zeroes such as 0.00123. Admittedly it works for my specific application as all my numbers are between 1 and 10000; so honestly I can't be bothered trying to make it universal due to time constraints.


So, is there a simple pre-defined function or simple way of doing such a simple task that I have completely missed? I ultimately would like to know of a simple significant figure rounding function that works all the time and is much less complicated than what I've given here. I believe that if no such solution exists, then (1) a solution for this task needs to be documented so that people can search for it and (2) the shortcoming in lack of said function needs to be addressed to Wolfram Research. Does anyone have any suggestions on a pre-defined, pre-established or a custom function of their own that improves upon my current suggestion?



Answer



Please tell me if this simplified function does what you want:


f[x_, n_] := Round[x, 10^(1 - n + ⌊ Log10 @ Abs @ x ⌋)] ~SetPrecision~ n

Test:


Table[f[x*Pi, 4], {x, {1/100, 1/10, 1, 10, 100}}]

% // FullForm



{0.03142, 0.3142, 3.142, 31.42, 314.2}

List[0.03142`4., 0.3142`4., 3.142`4., 31.42`4., 314.2`4.]



Update


The OP wrote:




I understand that there is a difference in the 'implied precision' between the number 0.5 and 1/2 when entered in Mathematica. But my request is to perform a very simple calculation: consider the number 1.004 and double it. The answer is 2.008. Then round it to 3 sig. fig, the answer is 2.01. Take that number, divide it by two/multiply by half/multiply by 0.5 (mathematically equivalent). The mathematical answer is 1.005. I did not ask to round the final answer to 3 sig. fig. as that could be done by doing f to the final answer. Is this possible?



I suspect that I am failing to comprehend the needs that are behind this request and as such that my recommendations may be inadequate or inappropriate. However I am trying both to understand and to help, so I shall venture forward.


When performing the following operations:


1.004*2
f[%, 3]
x = %/2


2.008


2.01

1.01

The result is as desired except in the output formatting; the underlying value of x is correct as can be seen with FullForm:


FullForm[x]


1.005`3.


Increasing its precision also results in all four digits being formatted in output:


SetPrecision[x, 4]


1.005

If this is not an acceptable method then perhaps setting a higher precision beforehand would be usable.


1.004*2
f[%, 3]

f[%, 4]
%/2


2.008

2.01

2.010


1.005

If this too is not acceptable then to the best of my knowledge Mathematica has no floating point format that is, as you seem to want a fundamentally different precision arithmetic than what is implemented in Mathematica.


Perhaps working with Rational values could work for you. As a rough and partial example:


SetAttributes[num, NHoldAll]

num /: num[x_] * (num[y_] | y_.) := num[x * y]
num /: num[x_] + (num[y_] | y_.) := num[x + y]

Format[num[x_]] := N[x]


g[num[x_] | x_, n_] := num @ Round[x, 10^(1 - n + ⌊Log10@Abs@x⌋)]

Now:


g[1.00412, 4]  (* step to show that g may be used more than once *)

%*2

g[%, 3]


%/2


1.004

2.008

2.01

1.005




Related Q&A's:



Comments

Popular posts from this blog

front end - keyboard shortcut to invoke Insert new matrix

I frequently need to type in some matrices, and the menu command Insert > Table/Matrix > New... allows matrices with lines drawn between columns and rows, which is very helpful. I would like to make a keyboard shortcut for it, but cannot find the relevant frontend token command (4209405) for it. Since the FullForm[] and InputForm[] of matrices with lines drawn between rows and columns is the same as those without lines, it's hard to do this via 3rd party system-wide text expanders (e.g. autohotkey or atext on mac). How does one assign a keyboard shortcut for the menu item Insert > Table/Matrix > New... , preferably using only mathematica? Thanks! Answer In the MenuSetup.tr (for linux located in the $InstallationDirectory/SystemFiles/FrontEnd/TextResources/X/ directory), I changed the line MenuItem["&New...", "CreateGridBoxDialog"] to read MenuItem["&New...", "CreateGridBoxDialog", MenuKey["m", Modifiers-...

How to thread a list

I have data in format data = {{a1, a2}, {b1, b2}, {c1, c2}, {d1, d2}} Tableform: I want to thread it to : tdata = {{{a1, b1}, {a2, b2}}, {{a1, c1}, {a2, c2}}, {{a1, d1}, {a2, d2}}} Tableform: And I would like to do better then pseudofunction[n_] := Transpose[{data2[[1]], data2[[n]]}]; SetAttributes[pseudofunction, Listable]; Range[2, 4] // pseudofunction Here is my benchmark data, where data3 is normal sample of real data. data3 = Drop[ExcelWorkBook[[Column1 ;; Column4]], None, 1]; data2 = {a #, b #, c #, d #} & /@ Range[1, 10^5]; data = RandomReal[{0, 1}, {10^6, 4}]; Here is my benchmark code kptnw[list_] := Transpose[{Table[First@#, {Length@# - 1}], Rest@#}, {3, 1, 2}] &@list kptnw2[list_] := Transpose[{ConstantArray[First@#, Length@# - 1], Rest@#}, {3, 1, 2}] &@list OleksandrR[list_] := Flatten[Outer[List, List@First[list], Rest[list], 1], {{2}, {1, 4}}] paradox2[list_] := Partition[Riffle[list[[1]], #], 2] & /@ Drop[list, 1] RM[list_] := FoldList[Transpose[{First@li...

plotting - How to draw lines between specified dots on ListPlot?

I would like to create a plot where I have unconnected dots and some connected. So far, I have figured out how to draw the dots. My code is the following: ListPlot[{{1, 1}, {2, 2}, {3, 3}, {4, 4}, {1, 4}, {2, 5}, {3, 6}, {4, 7}, {1, 7}, {2, 8}, {3, 9}, {4, 10}, {1, 10}, {2, 11}, {3, 12}, {4,13}, {2.5, 7}}, Ticks -> {{1, 2, 3, 4}, None}, AxesStyle -> Thin, TicksStyle -> Directive[Black, Bold, 12], Mesh -> Full] I have thought using ListLinePlot command, but I don't know how to specify to the command to draw only selected lines between the dots. Do have any suggestions/hints on how to do that? Thank you. Answer One possibility would be to use Epilog with Line : ListPlot[ {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {1, 4}, {2, 5}, {3, 6}, {4, 7}, {1, 7}, {2, 8}, {3, 9}, {4, 10}, {1, 10}, {2, 11}, {3, 12}, {4, 13}, {2.5, 7}}, Ticks -> {{1, 2, 3, 4}, None}, AxesStyle -> Thin, TicksStyle -> Directive[Black, Bold, 12], Mesh -> Full, Epilog -> { Line[ ...