Skip to content

FLOP weights

Weighted FLOP counting

The counted_float package contains a set of default, built-in FLOP weights, based on both empirical measurements and theoretical estimates of the relative cost of different floating point operations.

See Methodology for the rationale behind the choice of data sources and methodology, and CPU architecture scope for the CPUs covered.

>>> from counted_float.config import get_active_flop_weights
>>> get_active_flop_weights().show()

{
    FlopType.MINUS      [-x]            :   0.45000
    FlopType.ABS        [abs(x)]        :   0.70000
    FlopType.ADD        [x+y]           :   1.00000
    FlopType.COMP       [x<=y]          :   1.00000
    FlopType.SUB        [x-y]           :   1.00000
    FlopType.MUL        [x*y]           :   1.40000
    FlopType.RND        [round]         :   1.80000
    FlopType.F2I        [float->int]    :   2.00000
    FlopType.I2F        [int->float]    :   2.00000
    FlopType.DIV        [x/y]           :   5.50000
    FlopType.SQRT       [sqrt(x)]       :   7.50000
    FlopType.EXP2       [2^x]           :  16.00000
    FlopType.EXP        [e^x]           :  18.00000
    FlopType.LOG        [log(x)]        :  18.00000
    FlopType.EXP10      [10^x]          :  22.00000
    FlopType.LOG2       [log2(x)]       :  22.00000
    FlopType.LOG10      [log10(x)]      :  24.00000
    FlopType.COS        [cos(x)]        :  30.00000
    FlopType.SIN        [sin(x)]        :  30.00000
    FlopType.POW        [x^y]           :  40.00000
    FlopType.TAN        [tan(x)]        :  40.00000
    FlopType.CBRT       [cbrt(x)]       :  45.00000
}

Note that these weights are rounded up to the ~10% closest semi-round number, reflecting a balance between accuracy and readability, while conveying the message that these weights should be used as approximations only. See below for the different rounding modes.

These weights will be used by default when extracting total weighted flop costs:

import math
from counted_float import CountedFloat, FlopCountingContext


cf1 = CountedFloat(1.73)
cf2 = CountedFloat(2.94)

with FlopCountingContext() as ctx:
    _ = cf1 + cf2
    _ = cf1 ** cf2
    _ = math.log2(cf2)

flop_counts = ctx.flop_counts()
total_cost = flop_counts.total_weighted_cost()  # 1 + 40 + 22 = 63

Note that the total_weighted_cost method will use the default flop weights as returned by get_flop_weights(). This can be overridden by either configuring different flop weights (see next section) or by setting the weights argument of the total_weighted_cost() method.

Configuring FLOP weights

We showed earlier that the get_flop_weights() function returns the default FLOP weights. We can change this by using the set_flop_weights() function, which takes a FlopWeights object as an argument. This way we can configure flop weights that might be obtained using benchmarks run on the target hardware (see Benchmarking).

from counted_float.config import set_active_flop_weights
from counted_float import FlopWeights

set_active_flop_weights(weights=FlopWeights(...))  # insert own weights here

Inspecting built-in data

Default, pre-aggregated flop weights

Built-in flop weights can be inspected using the following functions:

from counted_float.config import get_default_consensus_flop_weights

>>> get_default_consensus_flop_weights(rounding_mode=None).show()

{
    FlopType.MINUS      [-x]            :   0.43688
    FlopType.ABS        [abs(x)]        :   0.71585
    FlopType.COMP       [x<=y]          :   0.97866
    FlopType.SUB        [x-y]           :   0.99565
    FlopType.ADD        [x+y]           :   1.00000
    FlopType.MUL        [x*y]           :   1.39506
    FlopType.RND        [round]         :   1.78130
    FlopType.F2I        [float->int]    :   1.91125
    FlopType.I2F        [int->float]    :   1.91839
    FlopType.DIV        [x/y]           :   5.53385
    FlopType.SQRT       [sqrt(x)]       :   7.37309
    FlopType.EXP2       [2^x]           :  15.79616
    FlopType.EXP        [e^x]           :  17.45201
    FlopType.LOG        [log(x)]        :  18.93143
    FlopType.LOG2       [log2(x)]       :  22.29433
    FlopType.EXP10      [10^x]          :  22.93876
    FlopType.LOG10      [log10(x)]      :  24.56277
    FlopType.SIN        [sin(x)]        :  30.28970
    FlopType.COS        [cos(x)]        :  31.27413
    FlopType.POW        [x^y]           :  41.65022
    FlopType.TAN        [tan(x)]        :  41.99495
    FlopType.CBRT       [cbrt(x)]       :  44.15405
}

There are 3 rounding modes:

  • None -> no rounding
  • "nearest_int" -> round up/down to nearest integer, with a minimum of 1
  • "10%" -> round to nearest semi-round number within ~10% (default)

The default weights that are configured out-of-the-box in the package are the integer-rounded consensus weights.

Custom-aggregated flop weights

We can retrieve built-in flop weights in a more fine-grained manner, by custom filtering and then aggregating them with the geometric mean.

from counted_float.config import get_builtin_flop_weights

>>> get_builtin_flop_weights(key_filter="arm").show()

{
    FlopType.COMP       [x<=y]          :   0.65000
    FlopType.MINUS      [-x]            :   0.90000
    FlopType.ADD        [x+y]           :   1.00000
    FlopType.SUB        [x-y]           :   1.00000
    FlopType.ABS        [abs(x)]        :   1.10000
    FlopType.F2I        [float->int]    :   1.50000
    FlopType.MUL        [x*y]           :   1.50000
    FlopType.I2F        [int->float]    :   1.60000
    FlopType.RND        [round]         :   1.60000
    FlopType.DIV        [x/y]           :   6.00000
    FlopType.SQRT       [sqrt(x)]       :   7.50000
    FlopType.EXP2       [2^x]           :  16.00000
    FlopType.EXP        [e^x]           :  18.00000
    FlopType.LOG        [log(x)]        :  20.00000
    FlopType.LOG2       [log2(x)]       :  20.00000
    FlopType.EXP10      [10^x]          :  24.00000
    FlopType.LOG10      [log10(x)]      :  24.00000
    FlopType.COS        [cos(x)]        :  33.00000
    FlopType.SIN        [sin(x)]        :  33.00000
    FlopType.POW        [x^y]           :  40.00000
    FlopType.CBRT       [cbrt(x)]       :  45.00000
    FlopType.TAN        [tan(x)]        :  45.00000
}