Skip to content

Rounding Modes

Rounding in Fermat is accomplished by making calls to the RoundingProvider. This provider accepts a DecimalInterface as its input, and provides the rounded value as a string. The rounding provider provides two broad types of rounding, deterministic and non-deterministic (or semi-deterministic).

Rounding is Anything that Reduces Scale

Many people think of rounding as selecting the closest integer to a given number, with some kind of rule for what to do when you are half-way between two integers. However, rounding broadly covers any action that reduces the scale or precision of a number. Going from more digits to fewer digits is rounding regardless of how it is done.

This means that even operations like truncate() or floor() or ceil() are rounding. Since truncate is better handled by the Decimal object itself, due to its knowledge of the internal state of the object, that is not handled by the RoundingProvider. All other kinds of rounding offered in Fermat utilize the RoundingProvider however.

For this reason it is designed to be as lightweight as possible while still accomplishing its task.

The available modes are contained with the Samsara/Fermat/Enums/RoundingMode enum, and the relevant places in Fermat that allow you to specify a rounding mode are typed as such.

The default mode is RoundingMode::HalfEven. This is also the fallback mode if you ask for a non-existent rounding mode.

Setting the Rounding Mode

The rounding provider has a private static property where it stores the mode to use while rounding. This property can be read and set using public static methods, but as it is a static property it affects all rounding operations after a mode is changed, even those you don't directly call. This is useful in most cases, since it allows you to set the rounding mode once at the beginning of your program and then utilize that rounding mode in every call that is made to the library.

Rounding Mode Affects Many Operations Internally

Rounding occurs frequently in Fermat, since many operations produce more digits than the scale setting of your objects. The trigonometry functions, logarithmic function, and exponential functions all make a call to the RoundingProvider before returning a result. This means that selecting a rounding mode will affect the results you get from functions such as tan(), sin(), exp(), and ln().

In most cases this is not an issue, and would even be preferred to keep your results consistent with the other effects of rounding within the library. However, some modes such as Stochastic may produce results that are more inconsistent with the expectations of your program.

If you want to manually round an object once using a different mode, pass the mode as an argument to the round() method on your Decimal object instead of setting a new default more in the RoundingProvider. When done in this way, the provided mode will only be used for that one operation without affecting the default more for any other operations.

See Also

The exact signatures associated with the RoundingProvider can be found in the Rounding Provider Reference Page

Available Modes

Rounding Is Base-10 Referenced

As noted in other places, anything related to scale in this library is specific to base-10. While you can still round in other bases, the operations will be performed on the base-10 representation of the number instead of the base the Decimal object is in.

Examples Assume Rounding to the Closest Integer

In all of the examples given below, they are showing what the expected outputs would be if RoundingProvider::round($decimal, $places) was called with the example value for $decimal and 0 for $places. If a number with more digits were provided and a different value for $places was used, these rounding modes would all round towards a different target digit.

The examples describe the behavior if the $places argument is omitted, since its default value is 0. But you could just as easily use any mode to round to the nearest tenth by passing 1 for the $places argument.

Half Up

This rounding mode rounds the number towards positive infinity when halfway between two values.

Examples

Using the "Half Up" mode:

1.5 -> 2

Using the "Half Up" mode:

-1.5 -> -1

Using the "Half Up" mode:

2.5 -> 3

Using the "Half Up" mode:

-2.5 -> -2

Half Down

This rounding mode rounds the number towards negative infinity when halfway between two values.

Examples

Using the "Half Down" mode:

1.5 -> 1

Using the "Half Down" mode:

-1.5 -> -2

Using the "Half Down" mode:

2.5 -> 2

Using the "Half Down" mode:

-2.5 -> -3

Half Even

This rounding mode rounds the number towards the nearest even number when halfway between two values.

Examples

Using the "Half Even" mode:

1.5 -> 2

Using the "Half Even" mode:

-1.5 -> -2

Using the "Half Even" mode:

2.5 -> 2

Using the "Half Even" mode:

-2.5 -> -2

Half Odd

This rounding mode rounds the number towards the nearest odd number when halfway between two values.

Examples

Using the "Half Odd" mode:

1.5 -> 1

Using the "Half Odd" mode:

-1.5 -> -1

Using the "Half Odd" mode:

2.5 -> 3

Using the "Half Odd" mode:

-2.5 -> -3

Half Zero

This rounding mode rounds the number towards zero when halfway between two values.

Examples

Using the "Half Zero" mode:

1.5 -> 1

Using the "Half Zero" mode:

-1.5 -> -1

Using the "Half Zero" mode:

2.5 -> 2

Using the "Half Zero" mode:

-2.5 -> -2

Half Infinity

This rounding mode rounds the number towards the nearest infinity (positive or negative) when halfway between two values.

Examples

Using the "Half Infinity" mode:

1.5 -> 2

Using the "Half Infinity" mode:

-1.5 -> -2

Using the "Half Infinity" mode:

2.5 -> 3

Using the "Half Infinity" mode:

-2.5 -> -3

Ceil

This rounding mode rounds the number towards positive infinity, even for values which are not halfway between.

Examples

Using the "Ceil" mode:

1.5 -> 2

Using the "Ceil" mode:

-1.5 -> -1

Using the "Ceil" mode:

2.2 -> 3

Using the "Ceil" mode:

-2.2 -> -2

Floor

This rounding mode rounds the number towards negative infinity, even for values which are not halfway between.

Examples

Using the "Floor" mode:

1.5 -> 1

Using the "Floor" mode:

-1.5 -> -2

Using the "Floor" mode:

2.2 -> 2

Using the "Floor" mode:

-2.2 -> -3

Random

This rounding mode rounds the number in a direction that is randomly chosen when halfway between two values.

Examples

Using the "Random" mode:

1.5 -> 1 50% of the time 1.5 -> 2 50% of the time

Using the "Random" mode:

1.7 -> 2 100% of the time

Using the "Random" mode:

2.2 -> 2 100% of the time

Using the "Random" mode:

-2.5 -> -2 50% of the time -2.5 -> -3 50% of the time

Alternating

This rounding mode rounds the number in a direction that alternates as more calls to round() are made when halfway between two values.

Examples

Using the "Alternating" mode:

1.5 -> 2 on the first call 1.5 -> 1 on the second call

Using the "Alternating" mode:

1.7 -> 2 100% of the time

Using the "Alternating" mode:

2.2 -> 2 100% of the time

Using the "Alternating" mode:

-2.5 -> -3 on the first call -2.5 -> -2 on the second call

Stochastic

This rounding mode rounds the number in both directions in proportion to how close it is to both values. This occurs regardless of whether the number is halfway between. Please see the examples below for clarification.

Examples

Using the "Stochastic" mode:

1.5 -> 2 50% of the time 1.5 -> 1 50% of the time

Using the "Stochastic" mode:

1.7 -> 2 70% of the time 1.7 -> 1 30% of the time

Using the "Stochastic" mode:

2.2 -> 3 20% of the time 2.2 -> 2 80% of the time

Using the "Stochastic" mode:

-2.5 -> -3 50% of the time -2.5 -> -2 50% of the time