diff --git a/DESCRIPTION b/DESCRIPTION
index 745cc3291cdaf3af37270db0bca94dbb855d7a3f..85d879dbfc0ce0ee30c4b28d1ecc690e516fa9c7 100644
--- a/DESCRIPTION
+++ b/DESCRIPTION
@@ -43,6 +43,7 @@ Collate:
     'ProfitParticipation.R'
     'InsuranceTarif.R'
     'InsuranceContract.R'
+    'RoundingHelper.R'
     'contractGrid.R'
     'create_LIR_project.R'
     'exportInsuranceContract_xlsx.R'
diff --git a/NAMESPACE b/NAMESPACE
index 1588dbffacfa04548e63b4c79bc6f6635d35b78c..f392dc4a2815c46dfc02d8a466be74251152cbf9 100644
--- a/NAMESPACE
+++ b/NAMESPACE
@@ -55,6 +55,7 @@ export(PVfactory)
 export(PaymentTimeEnum)
 export(ProfitComponentsEnum)
 export(ProfitParticipation)
+export(RoundingHelper)
 export(SexEnum)
 export(TariffTypeEnum)
 export(age.exactRounded)
diff --git a/NEWS.md b/NEWS.md
index c0788597234931fc15aaa9f5edc69790e8f0884c..e832362cad37e8ad7fb69546df445a61faacbb15 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -2,8 +2,9 @@
 # Version 1.0.1: XXXXXXXXXXX XX, 2023
   * New parameters:
     - survivalBenefit: Generalize survival benefit vectors (previously: unit CF 1 at end of contract)
-    - gammaInZillmer: As a feature, include gamma costs (but not beta) in the Zillmer premium
-  * Improve test case generation: Als generate code to export sample contract to Excel
+    - gammaInZillmer: As a company-specific feature, include gamma costs (but not beta) in the Zillmer premium
+  * Improve test case generation: Also generate code to export sample contract to Excel
+  * Add feature to round intermediate value using a RoundingHelper class (stored in Parameters$Hooks$Rounding)
   
 
 # Version 1.0.0: October 27, 2023
diff --git a/R/InsuranceParameters.R b/R/InsuranceParameters.R
index 05baf81a194821aacd05596a293c05bf5c3d9dc9..f58adaef5b5562bd4bd1b69cc115f46fbfe0aa1b 100644
--- a/R/InsuranceParameters.R
+++ b/R/InsuranceParameters.R
@@ -70,7 +70,7 @@ setCost = function(costs, type, basis = "SumInsured", frequency = "PolicyPeriod"
 #'                           even if the insured has already dies (for term-fix insurances)
 #' @param unitcosts Unit costs (absolute monetary amount, during premium period)
 #' @param unitcosts.PolicyPeriod Unit costs (absolute monetary amount, during full contract period)
-#' 
+#'
 #' @returns an insurance cost structure (multi-dimensional matrix)
 #'
 #' @examples
@@ -350,14 +350,14 @@ InsuranceContract.Values = list(
 #'     \item{\code{$deathBenefit}}{The yearly relative death benefit (relative
 #'               to the initial sum insured); Can be set to a \code{function(len,
 #'               params, values)}, e.g. \code{deathBenefit = deathBenefit.linearDecreasing}}
-#'     \item{\code{$survivalBenefit}}{The survival benefit (relative to the initial 
+#'     \item{\code{$survivalBenefit}}{The survival benefit (relative to the initial
 #'               sum insured). By default, for (pure) endowments a survival benefit
-#'               of 1 is assumed at the end of the contract period. Other values 
-#'               (e.g. double survival benefit in endowments) or multiple survival 
-#'               payments during the contract period can be set with this parameter. 
-#'               A single numeric value indicates a single survival benefit at 
-#'               the end of the contract, a vector of numeric values indicates 
-#'               yearly survival benefits (not neccessarily with a survival 
+#'               of 1 is assumed at the end of the contract period. Other values
+#'               (e.g. double survival benefit in endowments) or multiple survival
+#'               payments during the contract period can be set with this parameter.
+#'               A single numeric value indicates a single survival benefit at
+#'               the end of the contract, a vector of numeric values indicates
+#'               yearly survival benefits (not neccessarily with a survival
 #'               payment at the end of the contract). Can be set to a \code{function(len,
 #'               params, values)} returning the benefit as a numeric value or vector.
 #'     \item{\code{$benefitParameter}}{(optional) Tariff-specific parameter to
@@ -452,6 +452,8 @@ InsuranceContract.Values = list(
 #'               that can be waived at all. }
 #' }
 #'
+#'
+#'
 #' ## Elements of sublist \code{InsuranceContract.ParameterDefault$Loadings}
 #'
 #' \describe{
@@ -568,6 +570,7 @@ InsuranceContract.Values = list(
 #'     \item{\code{$adjustPremiums}}{Adjust the resulting premiums. \code{function(premiums = list(premiums, coefficients, sumInsured), params, values)}}
 #'     \item{\code{$adjustPVForReserves}}{Adjust the absolute present value vectors used to derive reserves (e.g. when a sum rebate is subtracted from the gamma-cost reserves without influencing the premium calculation). \code{function(absPV, params, values)}}
 #'     \item{\code{$premiumRebateCalculation}}{Calculate the actual premium rebate from the rebate rate (e.g. when the premium rate is given as a yearly cost reduction applied to a single-premium contract). \code{function(premiumRebateRate, params = params, values = values)}}
+#'     \item{\code{$Rounding}}{A [RoundingHelper] object to specify rounding of intermediate values. Alternatively, a named list of rounding specifications can be given, which is used to construct a new [RoundingHelper] object.}}
 #' }
 #'
 #'
@@ -630,7 +633,7 @@ InsuranceContract.ParameterDefaults = list(
         benefitFrequencyOrder = function(params, ...) { if (is.null(params$Loadings$benefitFrequencyLoading)) 0 else -1}
     ),
     Costs = initializeCosts(),
-    minCosts = NULL,               # Base costs, which cannot be waived
+    minCosts = NULL,                            # Base costs, which cannot be waived
     Loadings = list( # Loadings can also be function(sumInsured, premiums)
         ongoingAlphaGrossPremium = 0,           # Acquisition cost that increase the gross premium
         tax = 0.04,                             # insurance tax, factor on each premium paid
@@ -694,7 +697,8 @@ InsuranceContract.ParameterDefaults = list(
       adjustPremiumCoefficients = NULL,  # function(coeff, type = type, premiums = premiums, params = params, values = values, premiumCalculationTime = premiumCalculationTime)
       adjustPremiums = NULL,             # function(premiums = list(premiums, coefficients, sumInsured), params, values)
       adjustPVForReserves = NULL,        # function(absPresentValues, params, values)
-      premiumRebateCalculation = NULL    # function(premiumRebateRate, params = params, values = values)
+      premiumRebateCalculation = NULL,   # function(premiumRebateRate, params = params, values = values)
+      Rounding = NULL                    # Rounding helper to specify particular rounding of values
     )
 );
 
diff --git a/R/InsuranceTarif.R b/R/InsuranceTarif.R
index 59539ee043ad8f79db76fd2c2b036bf4bc1b2090..0b95b2fb3ff2370608297785b1c555ad7ffe15d3 100644
--- a/R/InsuranceTarif.R
+++ b/R/InsuranceTarif.R
@@ -236,6 +236,12 @@ InsuranceTarif = R6Class(
 
       # Fill all remaining uninitialized values with their defaults, except for profit participation params
       self$Parameters = InsuranceContract.ParametersFallback(self$Parameters, InsuranceContract.ParameterDefaults, ppParameters = FALSE);
+
+      # Properly set up the rounding helper
+      if (is.null(self$Parameters$Hooks$Rounding)) self$Parameters$Hooks$Rounding = list()
+      if (is.list(self$Parameters$Hooks$Rounding)){
+        self$Parameters$Hooks$Rounding = do.call(RoundingHelper$new, self$Parameters$Hooks$Rounding)
+      }
     },
 
     #' @description create a copy of a tariff with certain parameters changed
@@ -271,6 +277,11 @@ InsuranceTarif = R6Class(
       if (!missing(tariffType)) cloned$tariffType = tariffType;
 
       cloned$Parameters = InsuranceContract.ParametersFill(cloned$Parameters, ...);
+      # Properly set up the rounding helper
+      if (is.null(cloned$Parameters$Hooks$Rounding)) cloned$Parameters$Hooks$Rounding = list()
+      if (is.list(cloned$Parameters$Hooks$Rounding)){
+        cloned$Parameters$Hooks$Rounding = do.call(RoundingHelper$new, cloned$Parameters$Hooks$Rounding)
+      }
       cloned
     },
 
@@ -364,7 +375,8 @@ InsuranceTarif = R6Class(
         } else {
           px = 1 - qx
         }
-        df = data.frame(age = ages, qx = qx, ix = ix, px = px, row.names = ages - age)
+        rd = params$Hooks$Rounding
+        df = data.frame(age = ages, qx = rd$round("qx", qx), ix = rd$round("ix", ix), px = rd$round("px", px), row.names = ages - age)
         df
       }
     },
@@ -727,6 +739,7 @@ InsuranceTarif = R6Class(
       if (getOption('LIC.debug.presentValueCashFlows', FALSE)) {
         browser();
       }
+      rd = params$Hooks$Rounding
 
       qq = self$getTransitionProbabilities(params, values);
 
@@ -746,17 +759,17 @@ InsuranceTarif = R6Class(
         (values$cashFlows[,"death_GrossPremium"] - values$cashFlows[,"premiums_advance"]);
 
       pv = cbind(
-        premiums = pvf$survival(values$cashFlows$premiums_advance, values$cashFlows$premiums_arrears,
-          m = params$ContractData$premiumFrequency, mCorrection = premiumFreqCorr),
-        additional_capital = pvf$survival(advance = values$cashFlows$additional_capital),
-        guaranteed = pvf$guaranteed(values$cashFlows$guaranteed_advance, values$cashFlows$guaranteed_arrears),
-        survival = pvf$survival(values$cashFlows$survival_advance, values$cashFlows$survival_arrears),
-        death_SumInsured = pvf$death(values$cashFlows$death_SumInsured),
-        disease_SumInsured = pvf$disease(values$cashFlows$disease_SumInsured),
-        death_GrossPremium = pvRefund,
-        death_Refund_past = pvRefundPast,
-        death_Refund_future = pvRefund - pvRefundPast,
-        death_PremiumFree = pvf$death(values$cashFlows$death_PremiumFree)
+        premiums = rd$round("PV Premiums", pvf$survival(values$cashFlows$premiums_advance, values$cashFlows$premiums_arrears,
+          m = params$ContractData$premiumFrequency, mCorrection = premiumFreqCorr)),
+        additional_capital = rd$round("PV AdditionalCapital", pvf$survival(advance = values$cashFlows$additional_capital)),
+        guaranteed = rd$round("PV Guarantee", pvf$guaranteed(values$cashFlows$guaranteed_advance, values$cashFlows$guaranteed_arrears)),
+        survival = rd$round("PV Survival", pvf$survival(values$cashFlows$survival_advance, values$cashFlows$survival_arrears)),
+        death_SumInsured = rd$round("PV Death", pvf$death(values$cashFlows$death_SumInsured)),
+        disease_SumInsured = rd$round("PV Disease", pvf$disease(values$cashFlows$disease_SumInsured)),
+        death_GrossPremium = rd$round("PV Death PremiumRefund", pvRefund),
+        death_Refund_past = rd$round("PV Death PremiumRefund Past", pvRefundPast),
+        death_Refund_future = rd$round("PV Death PremiumRefund Future", pvRefund - pvRefundPast),
+        death_PremiumFree = rd$round("PV Death PremiumFree", pvf$death(values$cashFlows$death_PremiumFree))
       );
 
       rownames(pv) <- pad0(rownames(qq), values$int$l);
@@ -817,6 +830,8 @@ InsuranceTarif = R6Class(
             pvfben$disease(cf$disease_SumInsured * cfCosts);
       }
 
+      rd = params$Hooks$Rounding;
+      pvc = rd$round("PV Costs", pvc)
       applyHook(hook = params$Hooks$adjustPresentValuesCosts, val = pvc, params = params, values = values, presentValues = presentValues)
     },
 
@@ -831,6 +846,7 @@ InsuranceTarif = R6Class(
       if (getOption('LIC.debug.getAbsCashFlows', FALSE)) {
         browser();
       }
+      rd = params$Hooks$Rounding;
 
       # TODO: Set up a nice list with coefficients for each type of cashflow,
       # rather than multiplying each item manually (this also mitigates the risk
@@ -854,6 +870,8 @@ InsuranceTarif = R6Class(
       values$cashFlows[,"death_SumInsured"] = values$cashFlows[,"death_SumInsured"] + values$cashFlows[,"death_GrossPremium"]
       colnames(values$cashFlows)[colnames(values$cashFlows) == "death_SumInsured"] = "death";
       # cashFlows[,"death_GrossPremium"] = NULL;
+      values$cashFlows = rd$round("CF absolute", values$cashFlows);
+
 
       # costs relative to sumInsured are already set up as the correct multiple
       # of the original SI, including the dynamic changes over time!
@@ -863,6 +881,7 @@ InsuranceTarif = R6Class(
         values$cashFlowsCosts[,,"NetPremium",] * values$premiums[["net"]] +
         # values$cashFlowsCosts[,,"Benefits",] * TODO!!!
         values$cashFlowsCosts[,,"Constant",];
+      values$cashFlowsCosts = rd$round("CF costs absolute", values$cashFlowsCosts);
 
       # Handle survival CF differently, because we don't want ".survival" in the column names!
       cbind(values$cashFlows, values$cashFlowsCosts[,,"survival"], values$cashFlowsCosts[,,-1])
@@ -897,6 +916,8 @@ InsuranceTarif = R6Class(
       pv[,"death_SumInsured"] = pv[,"death_SumInsured"] + pv[,"death_GrossPremium"]
       colnames(pv)[colnames(pv) == "death_SumInsured"] = "death";
 
+      pv = params$Hooks$Rounding$round("PV absolute", pv);
+
       cbind("premiums.unit" = values$presentValues[,"premiums"], pv)
     },
 
@@ -929,6 +950,10 @@ InsuranceTarif = R6Class(
         values$presentValuesCosts[,,"Constant",] / params$ContractData$sumInsured,
         dims = 2)
 
+      rd = params$Hooks$Rounding;
+      benefits = rd$round("PV abs benefits", benefits)
+      allBenefits = rd$round("PV abs allBenefits", allBenefits)
+      benefitsCosts = rd$round("PV abs benefitsCosts", benefitsCosts)
 
       cbind(
         benefits = benefits,
@@ -1146,7 +1171,7 @@ InsuranceTarif = R6Class(
         temp = temp /
           (enumerator / denominator * (1 + noMedicalExam.relative + extraChargeGrossPremium) + noMedicalExam - sumRebate - extraRebate);
       }
-      sumInsured = temp
+      sumInsured = params$Hooks$Rounding$round("sumInsured", temp);
 
       sumInsured
     },
@@ -1160,6 +1185,8 @@ InsuranceTarif = R6Class(
       if (getOption('LIC.debug.premiumCalculation', FALSE)) {
         browser();
       }
+      rd = params$Hooks$Rounding;
+
       loadings = params$Loadings;
       sumInsured = params$ContractData$sumInsured
       values$premiums = c(
@@ -1191,8 +1218,8 @@ InsuranceTarif = R6Class(
       coeff = self$getPremiumCoefficients("gross", pv * 0, pvCost * 0, premiums = values$premiums, params = params, values = values, premiumCalculationTime = premiumCalculationTime)
       enumerator  = sum(coeff[["SumInsured"]][["benefits"]] * pv) + sum(coeff[["SumInsured"]][["costs"]] * pvCost);
       denominator = sum(coeff[["Premium"   ]][["benefits"]] * pv) + sum(coeff[["Premium"   ]][["costs"]] * pvCost);
-      values$premiums[["unit.gross"]] = enumerator/ifelse(denominator == 0, 1, denominator) * (1 + loadings$ongoingAlphaGrossPremium);
-      values$premiums[["gross"]] = values$premiums[["unit.gross"]] * sumInsured;
+      values$premiums[["unit.gross"]] = rd$round("Premium gross unit", enumerator/ifelse(denominator == 0, 1, denominator) * (1 + loadings$ongoingAlphaGrossPremium));
+      values$premiums[["gross"]] = rd$round("Premium gross", values$premiums[["unit.gross"]] * sumInsured);
       coefficients[["gross"]] = coeff;
 
       # ======================================================================= =
@@ -1201,8 +1228,8 @@ InsuranceTarif = R6Class(
       coeff = self$getPremiumCoefficients("net", pv*0, pvCost*0, premiums = values$premiums, params = params, values = values, premiumCalculationTime = premiumCalculationTime)
       enumerator  = sum(coeff[["SumInsured"]][["benefits"]] * pv) + sum(coeff[["SumInsured"]][["costs"]] * pvCost);
       denominator = sum(coeff[["Premium"   ]][["benefits"]] * pv) + sum(coeff[["Premium"   ]][["costs"]] * pvCost);
-      values$premiums[["unit.net"]] = enumerator/ifelse(denominator == 0, 1, denominator);
-      values$premiums[["net"]] = values$premiums[["unit.net"]] * sumInsured;
+      values$premiums[["unit.net"]] = rd$round("Premium net unit", enumerator/ifelse(denominator == 0, 1, denominator));
+      values$premiums[["net"]] = rd$round("Premium net", values$premiums[["unit.net"]] * sumInsured);
       coefficients[["net"]] = coeff;
 
       # ======================================================================= =
@@ -1211,8 +1238,8 @@ InsuranceTarif = R6Class(
       coeff = self$getPremiumCoefficients("Zillmer", pv * 0, pvCost * 0, premiums = values$premiums, params = params, values = values, premiumCalculationTime = premiumCalculationTime);
       enumerator  = sum(coeff[["SumInsured"]][["benefits"]] * pv) + sum(coeff[["SumInsured"]][["costs"]] * pvCost);
       denominator = sum(coeff[["Premium"   ]][["benefits"]] * pv) + sum(coeff[["Premium"   ]][["costs"]] * pvCost);
-      values$premiums[["unit.Zillmer"]] = enumerator/ifelse(denominator == 0, 1, denominator);
-      values$premiums[["Zillmer"]] = values$premiums[["unit.Zillmer"]] * sumInsured;
+      values$premiums[["unit.Zillmer"]] = rd$round("Premium Zillmer unit", enumerator/ifelse(denominator == 0, 1, denominator));
+      values$premiums[["Zillmer"]] = rd$round("Premium Zillmer", values$premiums[["unit.Zillmer"]] * sumInsured);
       coefficients[["Zillmer"]] = coeff;
 
 
@@ -1220,6 +1247,7 @@ InsuranceTarif = R6Class(
       # Additional premium components (after gross premium)
       # ----------------------------------------------------------------------- -
       # The written premium is the gross premium with additional loadings, rebates, unit costs and taxes
+      # TODO: Think through, how each of the components should / could be rounded
       tax           = valueOrFunction(loadings$tax,          params = params, values = values);
       unitCosts     = valueOrFunction(loadings$unitcosts,    params = params, values = values);
       noMedicalExam = valueOrFunction(loadings$noMedicalExam,params = params, values = values);
@@ -1260,10 +1288,10 @@ InsuranceTarif = R6Class(
       premiumBeforeTax = premiumBeforeTax * (1 - premiumRebate - advanceProfitParticipationUnitCosts - partnerRebate);
       premiumBeforeTax.y = premiumBeforeTax * (1 + frequencyLoading);
       premiumBeforeTax = premiumBeforeTax.y / params$ContractData$premiumFrequency;
-      values$premiums[["written_yearly"]] = premiumBeforeTax.y * (1 + tax)
-      values$premiums[["written_beforetax"]] = premiumBeforeTax;
-      values$premiums[["tax"]] = premiumBeforeTax * tax;
-      values$premiums[["written"]] = premiumBeforeTax * (1 + tax);
+      values$premiums[["written_yearly"]] = rd$round("Premium written yearly", premiumBeforeTax.y * (1 + tax))
+      values$premiums[["written_beforetax"]] = rd$round("Premium written beforeTax", premiumBeforeTax);
+      values$premiums[["tax"]] = rd$round("Premium tax", premiumBeforeTax * tax);
+      values$premiums[["written"]] = rd$round("Premium written", values$premiums[["written_beforetax"]] + values$premiums[["tax"]]);
 
       applyHook(
         params$Hooks$adjustPremiums,
@@ -1281,6 +1309,7 @@ InsuranceTarif = R6Class(
       if (getOption('LIC.debug.reserveCalculation', FALSE)) {
         browser();
       }
+      rd = params$Hooks$Rounding;
       t = "0"
       securityFactor = (1 + valueOrFunction(params$Loadings$security, params = params, values = values));
       ppScheme      = params$ProfitParticipation$profitParticipationScheme;
@@ -1288,10 +1317,10 @@ InsuranceTarif = R6Class(
       absPV = applyHook(params$Hooks$adjustPVForReserves, values$absPresentValues, params = params, values = values);
 
       # Net, Zillmer and Gross reserves
-      resNet = absPV[,"benefitsAndRefund"] * securityFactor - values$premiums[["net"]] * absPV[,"premiums.unit"];
+      resNet = rd$round("Res net", absPV[,"benefitsAndRefund"] * securityFactor - values$premiums[["net"]] * absPV[,"premiums.unit"]);
       BWZcorr = ifelse(absPV[t, "premiums"] == 0, 0,
                        absPV[t, "Zillmer"] / absPV[t, "premiums"]) * absPV[,"premiums"];
-      resZ = resNet - BWZcorr;
+      resZ = rd$round("Res Zillmer", resNet - BWZcorr);
 
       resAdeq = absPV[,"benefitsAndRefund"] * securityFactor +
           absPV[,"alpha"] + absPV[,"beta"] + absPV[,"gamma"] -
@@ -1299,10 +1328,11 @@ InsuranceTarif = R6Class(
       if (params$Features$unitcostsInGross) {
           resAdeq = resAdeq + absPV[, "unitcosts"]
       }
+      resAdeq = rd$round("Res adequate", resAdeq)
 
-      resGamma = absPV[,"gamma"] -
+      resGamma = rd$round("Res gamma", absPV[,"gamma"] -
         ifelse(absPV[t, "premiums"] == 0, 0,
-               absPV[t, "gamma"] / absPV[t, "premiums"]) * absPV[,"premiums"]
+               absPV[t, "gamma"] / absPV[t, "premiums"]) * absPV[,"premiums"]);
 
 
       advanceProfitParticipation = 0;
@@ -1339,7 +1369,10 @@ InsuranceTarif = R6Class(
         resContractual = resAdeq + resGamma
         resReduction = resAdeq + alphaRefund;
       }
-      resConversion = resContractual * (1 - advanceProfitParticipation);
+      resContractual = rd$round("Res contractual", resContractual)
+      resReduction = rd$round("Res reduction", resReduction)
+
+      resConversion = rd$round("Res conversion", resContractual * (1 - advanceProfitParticipation));
       if (params$Features$surrenderIncludesCostsReserves) {
         resReduction = resReduction + resGamma;
       }
@@ -1379,6 +1412,7 @@ InsuranceTarif = R6Class(
           partnerRebate = valueOrFunction(params$Loadings$partnerRebate, params = params, values = values);
           surrenderValue = resReduction * (1 - advanceProfitParticipationUnitCosts - partnerRebate);
       }
+      surrenderValue = rd$round("Surrender Value", surrenderValue)
 
 
       # Calculate new sum insured after premium waiver
@@ -1392,6 +1426,7 @@ InsuranceTarif = R6Class(
       newSI = ifelse(premiumfreePV == 0, 0,
         (premiumfreeValue - absPV[,"death_Refund_past"] * securityFactor - c(Storno)) /
         premiumfreePV * params$ContractData$sumInsured);
+      newSI = rd$round("Premiumfree SI", newSI)
 
       cbind(res,
             "PremiumsPaid" = Reduce("+", values$absCashFlows$premiums_advance, accumulate = TRUE),
@@ -1443,6 +1478,7 @@ InsuranceTarif = R6Class(
       if (getOption('LIC.debug.reserveCalculationBalanceSheet', FALSE)) {
         browser();
       }
+      rd = params$Hooks$Rounding
       reserves = values$reserves;
       years = length(reserves[,"Zillmer"]);
       # Balance sheet reserves:
@@ -1496,7 +1532,7 @@ InsuranceTarif = R6Class(
                   "unearned Premiums"     = unearnedPremiums
       );
       rownames(res) <- rownames(reserves);
-      res
+      rd$round("Balance Sheet", res)
     },
 
     #' @description Calculate the profit participation given the contract
@@ -1549,6 +1585,7 @@ InsuranceTarif = R6Class(
     #' @details Not to be called directly, but implicitly by the [InsuranceContract] object.
     #'          All premiums, reserves and present values have already been calculated.
     premiumDecomposition = function(params, values) {
+      # TODO: No rounding applied yet!
       if (getOption('LIC.debug.premiumDecomposition', FALSE)) {
         browser();
       }
diff --git a/R/RoundingHelper.R b/R/RoundingHelper.R
new file mode 100644
index 0000000000000000000000000000000000000000..3f46ec8d6fb662406b2a7b0842c2c46e31b66cc1
--- /dev/null
+++ b/R/RoundingHelper.R
@@ -0,0 +1,113 @@
+#' @import R6
+NULL
+
+############# Class RoundingHelper ###########################################
+#' Helper object to define rounding rules for the InsuranceContract,
+#' InsuranceTarif and ProfitParticipation classes.
+#'
+#' @description The class \code{RoundingHelper} provides the code and settings
+#' to define numeric rounding rules for premiums, reserves, benefits etc. of
+#' a life insurance contract. By default, no rounding it applied.
+#'
+#' @param values Contract values calculated so far (in the \code{contract$Values}
+#'      list) then this method is called by the contract object
+#'
+#' @param premiumCalculationTime The time when the premiums should be
+#'        (re-)calculated according to the equivalence principle. A time 0
+#'        means the initial premium calculation at contract closing, later
+#'        premium calculation times can be used to re-calculate the new
+#'        premium after a contract change (possibly including an existing reserve)
+#'
+#' @examples
+#' # TODO
+#' @export
+RoundingHelper = R6Class(
+  "RoundingHelper",
+
+  ######################### PUBLIC METHODS ##################################
+  public  = list(
+    #' @field rounding The (named) list containing all declared rounding definitions
+    rounding  = list(),
+
+    #' @description Initialize the rounding settings
+    #' @details Sets up the rounding helper by giving a list of named entries, specifying rounding accuracy for each particular value
+    #'
+    #' @param ... named entries specifying rounding accuracy
+    #' @examples
+    #' rounding = RoundingHelper$new(raw = 0, hundred = -2, accurate = 4)
+    #' rounding$round("raw", c(1234.567891, 0.00012345, 1234))
+    #' rounding$round("hundred", c(1234.567891, 0.00012345, 1234))
+    #' rounding$round("accurate", c(1234.567891, 0.00012345, 1234))
+    #' rounding$round("non-existing", c(1234.567891, 0.00012345, 1234))
+    initialize = function(...) {
+      self$rounding = list(...)
+    },
+
+    #' @description Round the given values using the pre-defined accuracy
+    #' @details Rounds the given values using the accuracies defined in the
+    #'          internal rounding list (set either via the 'initialize' function
+    #'          or via a call to 'setRounding'. The accuracies are defined using
+    #'          a 'spec' identifier, which allows to define different accuracies
+    #'          for different uses
+    #'
+    #' @param spec the ID used for looking up the desired accuracy
+    #' @param value the values to be rounded according to 'spec'
+    #' @param ... currently unused
+    #' @examples
+    #' rounding = RoundingHelper$new(raw = 0, hundred = -2, accurate = 4)
+    #' rounding$round("raw", c(1234.567891, 0.00012345, 1234))
+    #' rounding$round("hundred", c(1234.567891, 0.00012345, 1234))
+    #' rounding$round("accurate", c(1234.567891, 0.00012345, 1234))
+    #' # If the given spec does not exist, no rounding it applied
+    #' rounding$round("non-existing", c(1234.567891, 0.00012345, 1234))
+    round = function(spec, value, ...) {
+      if (is.character(spec)) {
+        spec = self$getRounding(spec, ...)
+      }
+      if (is.function(spec)) {
+        spec(value)
+      } else if (is.numeric(spec)) {
+        round(value, digits = spec)
+      } else {
+        value
+      }
+    },
+
+
+    #' @description Define rounding accuracy for a certain identifier
+    #' @details Configures the rounding helper for a given named entry,
+    #'          specifying rounding accuracy for each particular value
+    #'
+    #' @param key the ID used for looking up the desired accuracy
+    #' @param spec the rounding accuracy (number of digits)
+    #' @param ... currently unused
+    #' @examples
+    #' rounding = RoundingHelper$new(raw = 0, hundred = -2, accurate = 4)
+    #' rounding$round("raw", c(1234.567891, 0.00012345, 1234))
+    #' rounding$round("hundred", c(1234.567891, 0.00012345, 1234))
+    #' rounding$round("accurate", c(1234.567891, 0.00012345, 1234))
+    #' # If the given spec does not exist, no rounding it applied
+    #' rounding$round("non-existing", c(1234.567891, 0.00012345, 1234))
+    #' # Add a new spec with different settings:
+    #' rounding$setRounding("non-existing", 1)
+    #' rounding$round("non-existing", c(1234.567891, 0.00012345, 1234))
+    setRounding = function(key, spec, ...) {
+      self$rounding[[key]] = spec
+    },
+
+    #' @description Extract rounding accuracy for a certain identifier
+    #' @details Read out the rounding for a given named entry.
+    #'
+    #' @param key the ID used for looking up the desired accuracy
+    #' @param ... currently unused
+    #' @examples
+    #' rounding = RoundingHelper$new(raw = 0, hundred = -2, accurate = 4)
+    #' rounding$getRounding("hundred")
+    getRounding = function(key, ...) {
+      self$rounding[[key]]
+    }
+  )
+)
+
+
+
diff --git a/man/InsuranceContract.ParameterDefaults.Rd b/man/InsuranceContract.ParameterDefaults.Rd
index 1d54d19209aa28e9ced5b7c3f6e9fc90654ad935..6058f9b55d98bc915828e2fde1ce25a3df0f8a4b 100644
--- a/man/InsuranceContract.ParameterDefaults.Rd
+++ b/man/InsuranceContract.ParameterDefaults.Rd
@@ -108,6 +108,16 @@ describes the annuity unit payments for all years}
 \item{\code{$deathBenefit}}{The yearly relative death benefit (relative
 to the initial sum insured); Can be set to a \code{function(len,
               params, values)}, e.g. \code{deathBenefit = deathBenefit.linearDecreasing}}
+\item{\code{$survivalBenefit}}{The survival benefit (relative to the initial
+sum insured). By default, for (pure) endowments a survival benefit
+of 1 is assumed at the end of the contract period. Other values
+(e.g. double survival benefit in endowments) or multiple survival
+payments during the contract period can be set with this parameter.
+A single numeric value indicates a single survival benefit at
+the end of the contract, a vector of numeric values indicates
+yearly survival benefits (not neccessarily with a survival
+payment at the end of the contract). Can be set to a \code{function(len,
+              params, values)} returning the benefit as a numeric value or vector.
 \item{\code{$benefitParameter}}{(optional) Tariff-specific parameter to
 indicate special benefit conditions (e.g. for non-constant benefits
 the initial starting value, or a minimum benefit, etc.). This
diff --git a/man/InsuranceContract.ParameterStructure.Rd b/man/InsuranceContract.ParameterStructure.Rd
index e02511618bc07ea13ac930e92c1a763a8fa23343..a058cf4c3db6a9ebef2f81df33a33293fdf2ced9 100644
--- a/man/InsuranceContract.ParameterStructure.Rd
+++ b/man/InsuranceContract.ParameterStructure.Rd
@@ -5,7 +5,7 @@
 \alias{InsuranceContract.ParameterStructure}
 \title{Full insurance contract parameter structure.}
 \format{
-An object of class \code{list} of length 9.
+An object of class \code{list} of length 10.
 }
 \usage{
 InsuranceContract.ParameterStructure
diff --git a/man/InsuranceTarif.Rd b/man/InsuranceTarif.Rd
index 224ae9971f5d519ab83153a71b1ac4b502227d1d..0de7e6e8a14623f73bee73832a21d2881d1e2cba 100644
--- a/man/InsuranceTarif.Rd
+++ b/man/InsuranceTarif.Rd
@@ -146,6 +146,7 @@ all fields.}
 \item \href{#method-InsuranceTarif-getPremiumCF}{\code{InsuranceTarif$getPremiumCF()}}
 \item \href{#method-InsuranceTarif-getAnnuityCF}{\code{InsuranceTarif$getAnnuityCF()}}
 \item \href{#method-InsuranceTarif-getDeathCF}{\code{InsuranceTarif$getDeathCF()}}
+\item \href{#method-InsuranceTarif-getSurvivalCF}{\code{InsuranceTarif$getSurvivalCF()}}
 \item \href{#method-InsuranceTarif-getBasicCashFlows}{\code{InsuranceTarif$getBasicCashFlows()}}
 \item \href{#method-InsuranceTarif-getCashFlows}{\code{InsuranceTarif$getCashFlows()}}
 \item \href{#method-InsuranceTarif-getCashFlowsCosts}{\code{InsuranceTarif$getCashFlowsCosts()}}
@@ -514,7 +515,7 @@ period (after potential deferral period!)
 \subsection{Arguments}{
 \if{html}{\out{<div class="arguments">}}
 \describe{
-\item{\code{len}}{The desired length of the returned data frame (the number of contract periods desire)}
+\item{\code{len}}{The desired length of the returned data frame (the number of contract periods desired)}
 
 \item{\code{params}}{Contract-specific, full set of parameters of the contract
 (merged parameters of the defaults, the tariff, the profit participation
@@ -529,6 +530,37 @@ list) then this method is called by the contract object}
 Not to be called directly, but implicitly by the \link{InsuranceContract} object.
 }
 
+}
+\if{html}{\out{<hr>}}
+\if{html}{\out{<a id="method-InsuranceTarif-getSurvivalCF"></a>}}
+\if{latex}{\out{\hypertarget{method-InsuranceTarif-getSurvivalCF}{}}}
+\subsection{Method \code{getSurvivalCF()}}{
+Returns the unit survival cash flow profile for the whole contract
+period (after potential deferral period!)
+\itemize{
+\item a single numeric value indicates a single survival payment at the end of the contract
+\item a vector of numeric values indicates potentially multiple survival payments for the whole contract period (paddded with 0 to the full contract length if shorter)
+}
+\subsection{Usage}{
+\if{html}{\out{<div class="r">}}\preformatted{InsuranceTarif$getSurvivalCF(len, params, values)}\if{html}{\out{</div>}}
+}
+
+\subsection{Arguments}{
+\if{html}{\out{<div class="arguments">}}
+\describe{
+\item{\code{params}}{Contract-specific, full set of parameters of the contract
+(merged parameters of the defaults, the tariff, the profit participation
+scheme and the contract)}
+
+\item{\code{values}}{Contract values calculated so far (in the \code{contract$Values}
+list) then this method is called by the contract object}
+}
+\if{html}{\out{</div>}}
+}
+\subsection{Details}{
+Not to be called directly, but implicitly by the \link{InsuranceContract} object.
+}
+
 }
 \if{html}{\out{<hr>}}
 \if{html}{\out{<a id="method-InsuranceTarif-getBasicCashFlows"></a>}}
diff --git a/man/RoundingHelper.Rd b/man/RoundingHelper.Rd
new file mode 100644
index 0000000000000000000000000000000000000000..c8664bb84c0021b99584b03b0456c12d8022f93e
--- /dev/null
+++ b/man/RoundingHelper.Rd
@@ -0,0 +1,240 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/RoundingHelper.R
+\name{RoundingHelper}
+\alias{RoundingHelper}
+\title{Helper object to define rounding rules for the InsuranceContract,
+InsuranceTarif and ProfitParticipation classes.}
+\description{
+The class \code{RoundingHelper} provides the code and settings
+to define numeric rounding rules for premiums, reserves, benefits etc. of
+a life insurance contract. By default, no rounding it applied.
+}
+\examples{
+# TODO
+
+## ------------------------------------------------
+## Method `RoundingHelper$new`
+## ------------------------------------------------
+
+rounding = RoundingHelper$new(raw = 0, hundred = -2, accurate = 4)
+rounding$round("raw", c(1234.567891, 0.00012345, 1234))
+rounding$round("hundred", c(1234.567891, 0.00012345, 1234))
+rounding$round("accurate", c(1234.567891, 0.00012345, 1234))
+rounding$round("non-existing", c(1234.567891, 0.00012345, 1234))
+
+## ------------------------------------------------
+## Method `RoundingHelper$round`
+## ------------------------------------------------
+
+rounding = RoundingHelper$new(raw = 0, hundred = -2, accurate = 4)
+rounding$round("raw", c(1234.567891, 0.00012345, 1234))
+rounding$round("hundred", c(1234.567891, 0.00012345, 1234))
+rounding$round("accurate", c(1234.567891, 0.00012345, 1234))
+# If the given spec does not exist, no rounding it applied
+rounding$round("non-existing", c(1234.567891, 0.00012345, 1234))
+
+## ------------------------------------------------
+## Method `RoundingHelper$setRounding`
+## ------------------------------------------------
+
+rounding = RoundingHelper$new(raw = 0, hundred = -2, accurate = 4)
+rounding$round("raw", c(1234.567891, 0.00012345, 1234))
+rounding$round("hundred", c(1234.567891, 0.00012345, 1234))
+rounding$round("accurate", c(1234.567891, 0.00012345, 1234))
+# If the given spec does not exist, no rounding it applied
+rounding$round("non-existing", c(1234.567891, 0.00012345, 1234))
+# Add a new spec with different settings:
+rounding$setRounding("non-existing", 1)
+rounding$round("non-existing", c(1234.567891, 0.00012345, 1234))
+
+## ------------------------------------------------
+## Method `RoundingHelper$getRounding`
+## ------------------------------------------------
+
+rounding = RoundingHelper$new(raw = 0, hundred = -2, accurate = 4)
+rounding$getRounding("hundred")
+}
+\section{Public fields}{
+\if{html}{\out{<div class="r6-fields">}}
+\describe{
+\item{\code{rounding}}{The (named) list containing all declared rounding definitions}
+}
+\if{html}{\out{</div>}}
+}
+\section{Methods}{
+\subsection{Public methods}{
+\itemize{
+\item \href{#method-RoundingHelper-new}{\code{RoundingHelper$new()}}
+\item \href{#method-RoundingHelper-round}{\code{RoundingHelper$round()}}
+\item \href{#method-RoundingHelper-setRounding}{\code{RoundingHelper$setRounding()}}
+\item \href{#method-RoundingHelper-getRounding}{\code{RoundingHelper$getRounding()}}
+\item \href{#method-RoundingHelper-clone}{\code{RoundingHelper$clone()}}
+}
+}
+\if{html}{\out{<hr>}}
+\if{html}{\out{<a id="method-RoundingHelper-new"></a>}}
+\if{latex}{\out{\hypertarget{method-RoundingHelper-new}{}}}
+\subsection{Method \code{new()}}{
+Initialize the rounding settings
+\subsection{Usage}{
+\if{html}{\out{<div class="r">}}\preformatted{RoundingHelper$new(...)}\if{html}{\out{</div>}}
+}
+
+\subsection{Arguments}{
+\if{html}{\out{<div class="arguments">}}
+\describe{
+\item{\code{...}}{named entries specifying rounding accuracy}
+}
+\if{html}{\out{</div>}}
+}
+\subsection{Details}{
+Sets up the rounding helper by giving a list of named entries, specifying rounding accuracy for each particular value
+}
+
+\subsection{Examples}{
+\if{html}{\out{<div class="r example copy">}}
+\preformatted{rounding = RoundingHelper$new(raw = 0, hundred = -2, accurate = 4)
+rounding$round("raw", c(1234.567891, 0.00012345, 1234))
+rounding$round("hundred", c(1234.567891, 0.00012345, 1234))
+rounding$round("accurate", c(1234.567891, 0.00012345, 1234))
+rounding$round("non-existing", c(1234.567891, 0.00012345, 1234))
+}
+\if{html}{\out{</div>}}
+
+}
+
+}
+\if{html}{\out{<hr>}}
+\if{html}{\out{<a id="method-RoundingHelper-round"></a>}}
+\if{latex}{\out{\hypertarget{method-RoundingHelper-round}{}}}
+\subsection{Method \code{round()}}{
+Round the given values using the pre-defined accuracy
+\subsection{Usage}{
+\if{html}{\out{<div class="r">}}\preformatted{RoundingHelper$round(spec, value, ...)}\if{html}{\out{</div>}}
+}
+
+\subsection{Arguments}{
+\if{html}{\out{<div class="arguments">}}
+\describe{
+\item{\code{spec}}{the ID used for looking up the desired accuracy}
+
+\item{\code{value}}{the values to be rounded according to 'spec'}
+
+\item{\code{...}}{currently unused}
+}
+\if{html}{\out{</div>}}
+}
+\subsection{Details}{
+Rounds the given values using the accuracies defined in the
+internal rounding list (set either via the 'initialize' function
+or via a call to 'setRounding'. The accuracies are defined using
+a 'spec' identifier, which allows to define different accuracies
+for different uses
+}
+
+\subsection{Examples}{
+\if{html}{\out{<div class="r example copy">}}
+\preformatted{rounding = RoundingHelper$new(raw = 0, hundred = -2, accurate = 4)
+rounding$round("raw", c(1234.567891, 0.00012345, 1234))
+rounding$round("hundred", c(1234.567891, 0.00012345, 1234))
+rounding$round("accurate", c(1234.567891, 0.00012345, 1234))
+# If the given spec does not exist, no rounding it applied
+rounding$round("non-existing", c(1234.567891, 0.00012345, 1234))
+}
+\if{html}{\out{</div>}}
+
+}
+
+}
+\if{html}{\out{<hr>}}
+\if{html}{\out{<a id="method-RoundingHelper-setRounding"></a>}}
+\if{latex}{\out{\hypertarget{method-RoundingHelper-setRounding}{}}}
+\subsection{Method \code{setRounding()}}{
+Define rounding accuracy for a certain identifier
+\subsection{Usage}{
+\if{html}{\out{<div class="r">}}\preformatted{RoundingHelper$setRounding(key, spec, ...)}\if{html}{\out{</div>}}
+}
+
+\subsection{Arguments}{
+\if{html}{\out{<div class="arguments">}}
+\describe{
+\item{\code{key}}{the ID used for looking up the desired accuracy}
+
+\item{\code{spec}}{the rounding accuracy (number of digits)}
+
+\item{\code{...}}{currently unused}
+}
+\if{html}{\out{</div>}}
+}
+\subsection{Details}{
+Configures the rounding helper for a given named entry,
+specifying rounding accuracy for each particular value
+}
+
+\subsection{Examples}{
+\if{html}{\out{<div class="r example copy">}}
+\preformatted{rounding = RoundingHelper$new(raw = 0, hundred = -2, accurate = 4)
+rounding$round("raw", c(1234.567891, 0.00012345, 1234))
+rounding$round("hundred", c(1234.567891, 0.00012345, 1234))
+rounding$round("accurate", c(1234.567891, 0.00012345, 1234))
+# If the given spec does not exist, no rounding it applied
+rounding$round("non-existing", c(1234.567891, 0.00012345, 1234))
+# Add a new spec with different settings:
+rounding$setRounding("non-existing", 1)
+rounding$round("non-existing", c(1234.567891, 0.00012345, 1234))
+}
+\if{html}{\out{</div>}}
+
+}
+
+}
+\if{html}{\out{<hr>}}
+\if{html}{\out{<a id="method-RoundingHelper-getRounding"></a>}}
+\if{latex}{\out{\hypertarget{method-RoundingHelper-getRounding}{}}}
+\subsection{Method \code{getRounding()}}{
+Extract rounding accuracy for a certain identifier
+\subsection{Usage}{
+\if{html}{\out{<div class="r">}}\preformatted{RoundingHelper$getRounding(key, ...)}\if{html}{\out{</div>}}
+}
+
+\subsection{Arguments}{
+\if{html}{\out{<div class="arguments">}}
+\describe{
+\item{\code{key}}{the ID used for looking up the desired accuracy}
+
+\item{\code{...}}{currently unused}
+}
+\if{html}{\out{</div>}}
+}
+\subsection{Details}{
+Read out the rounding for a given named entry.
+}
+
+\subsection{Examples}{
+\if{html}{\out{<div class="r example copy">}}
+\preformatted{rounding = RoundingHelper$new(raw = 0, hundred = -2, accurate = 4)
+rounding$getRounding("hundred")
+}
+\if{html}{\out{</div>}}
+
+}
+
+}
+\if{html}{\out{<hr>}}
+\if{html}{\out{<a id="method-RoundingHelper-clone"></a>}}
+\if{latex}{\out{\hypertarget{method-RoundingHelper-clone}{}}}
+\subsection{Method \code{clone()}}{
+The objects of this class are cloneable with this method.
+\subsection{Usage}{
+\if{html}{\out{<div class="r">}}\preformatted{RoundingHelper$clone(deep = FALSE)}\if{html}{\out{</div>}}
+}
+
+\subsection{Arguments}{
+\if{html}{\out{<div class="arguments">}}
+\describe{
+\item{\code{deep}}{Whether to make a deep clone.}
+}
+\if{html}{\out{</div>}}
+}
+}
+}
diff --git a/tests/testthat/test-RoundingHelper.R b/tests/testthat/test-RoundingHelper.R
new file mode 100644
index 0000000000000000000000000000000000000000..e80406c1711ee41b2869db2cd07965063d5e5914
--- /dev/null
+++ b/tests/testthat/test-RoundingHelper.R
@@ -0,0 +1,59 @@
+test_that("Rounding Helper", {
+
+    rounding = RoundingHelper$new(test = 2, gross.premium = 0, "Sum Insured" = -2)
+
+    rounding$rounding
+
+    expect_equal(
+        rounding$round("test", c(2*10^(-8:5), 987654321.987654321)),
+        c(0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.02, 0.20, 2.00, 20.00, 200.00, 2000.00, 20000.00, 200000.00, 987654321.99)
+    )
+
+    expect_equal(
+        rounding$round("gross.premium", c(2*10^(-8:5), 987654321.987654321)),
+        c(0, 0, 0, 0, 0, 0, 0, 0, 2, 20, 200, 2000, 20000, 200000, 987654322)
+    )
+
+    expect_equal(
+        rounding$round("Sum Insured", c(2*10^(-8:5), 987654321.987654321)),
+        c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200, 2000, 20000, 200000, 987654300)
+    )
+
+    expect_equal(
+        rounding$round("NotExisting", c(2*10^(-8:5), 987654321.987654321)),
+        c(2*10^(-8:5), 987654321.987654321)
+    )
+
+})
+
+test_that("Calculation of sumInsured from premium", {
+    library(MortalityTables)
+    mortalityTables.load("Austria_Census")
+
+    Tarif.EndowmentSI = InsuranceTarif$new(
+        name = "Example Tariff - Endowment",
+        type = "endowment",
+        tarif = "E1-RP",
+        desc = "An endowment with regular premiums (standard tariff)",
+        age = 40, policyPeriod = 20,
+
+        mortalityTable = mort.AT.census.2011.unisex,
+        cost = initializeCosts(alpha = 0.04, gamma.contract = 0.0005, unitcosts = 10),
+        i = 0.03,
+        sumInsured = 10000,
+        contractClosing = as.Date("2020-09-01")
+    )
+    Tarif.EndowmentSI.rounded = Tarif.EndowmentSI$createModification(
+        Rounding = list("Premium gross" = 0, "Premium net" = 2)
+    )
+    Contract.sumInsured = InsuranceContract$new(
+        tarif = Tarif.EndowmentSI
+    )
+    Contract.sumInsured.rounded = InsuranceContract$new(
+        tarif = Tarif.EndowmentSI.rounded
+    )
+
+    expect_equal(Contract.sumInsured.rounded$Values$premiums[["gross"]], round(Contract.sumInsured$Values$premiums[["gross"]], 0))
+    expect_equal(Contract.sumInsured.rounded$Values$premiums[["net"]], round(Contract.sumInsured$Values$premiums[["net"]], 2))
+
+})
diff --git a/vignettes/using-the-lifeinsurer-package.Rmd b/vignettes/using-the-lifeinsurer-package.Rmd
index a8a7ebf49c20b43f56053dc73fe8f3d2c7acd97b..609f3f59e56d2331e1f40c9a0910cb0dd5b10845 100644
--- a/vignettes/using-the-lifeinsurer-package.Rmd
+++ b/vignettes/using-the-lifeinsurer-package.Rmd
@@ -1133,6 +1133,89 @@ contractGridPremium(
 ) %>% kableTable(digits = 2)
 ```
 
+
+# Rounding values
+
+In an ideal world, all calculations would be done with perfect accuracy. However,
+in reality insurance tariffs are often implemented in systems that support only 
+a limited number of digits. Or it is company policy to round premiums to whole 
+Euro or Dollar amounts.
+
+For this reason, the package also provides a `RoundingHelper` class that provides
+an easy interfact for rounding intermediate values in the calculation. The 
+instance of this class is stored in the tariff (and the contract) as 
+`$Parameters$Hooks$Rounding` and the methods of the `InsuranceTarif` make use
+of it in all places where rounding can typicall happen.
+
+Each place where a number/vector/matrix is rounded in the package uses a separate
+ID, which can and must be used to adjust the rounding behavior at that position.
+If no rounding setting is set, no rounding occurs and no accuracy is lost.
+
+An easy example of how rounding works is:
+```{r RoundingHelper}
+# Define three different rounding IDs / instances: "raw" with rounding to
+# the nearest integer, "hundred" with rounding to the nearest multiple of 
+# 100 and "accurate" rounded to the nearest multiple of 0.0001:
+rounding = RoundingHelper$new(raw = 0, hundred = -2, accurate = 4)
+
+# The rounding IDs are used as first argument in the rounding$round function:
+rounding$round("raw", c(1234.567891, 0.00012345, 1234))
+rounding$round("hundred", c(1234.567891, 0.00012345, 1234))
+rounding$round("accurate", c(1234.567891, 0.00012345, 1234))
+
+# If the given spec does not exist, no rounding it applied
+rounding$round("non-existing", c(1234.567891, 0.00012345, 1234))
+
+# Add a new spec with different settings:
+rounding$setRounding("non-existing", 1)
+rounding$round("non-existing", c(1234.567891, 0.00012345, 1234))
+```
+
+
+The `InsuranceTarif` class makes heavy use of these rounding settings. For 
+example, to round the gross premium to Euros and the net premium to cent, 
+one can use the setting `Rounding = list("Premium gross" = 0, "Premium net" = 2)`:
+
+```{r RoundingHelper.Contract}
+Tarif.EndowmentSI = InsuranceTarif$new(
+    type = "endowment",
+    tarif = "Endow1",
+    age = 40, policyPeriod = 20,
+
+    mortalityTable = mort.AT.census.2011.unisex,
+    cost = initializeCosts(alpha = 0.04, gamma.contract = 0.0005),
+    i = 0.03,
+    sumInsured = 10000,
+    contractClosing = as.Date("2020-09-01")
+)
+Tarif.EndowmentSI.rounded = Tarif.EndowmentSI$createModification(
+    Rounding = list("Premium gross" = 0, "Premium net" = 2)
+)
+Contract.sumInsured = InsuranceContract$new(tarif = Tarif.EndowmentSI)
+Contract.sumInsured.rounded = InsuranceContract$new(tarif = Tarif.EndowmentSI.rounded)
+
+
+# premiums of the original tariff:
+Contract.sumInsured$Values$premiums[c("unit.net", "net", "unit.gross", "gross")]
+# premiums of the tariff with rounding applied:
+Contract.sumInsured.rounded$Values$premiums[c("unit.net", "net", "unit.gross", "gross")]
+
+```
+
+Here is a list of all rounding IDs used throughout the InsuranceTarif class. 
+Each of them can be used to adjust rounding just one particular value/vector:
+
+```{r eval=TRUE,echo=FALSE,result='asis'}
+src = list.files(path = here::here("R"), pattern = ".R$", full.names = TRUE)
+filecontents = purrr::map(src, readLines) %>% unlist %>% as.vector
+results = stringr::str_extract(filecontents, "\\$round\\(\"([^\"]*)\"", group = 1)
+results = results[!is.na(results)]
+results = results[!(results %in% c("raw", "hundred", "accurate", "non-existing"))] %>% sort
+cat(paste('-', results), sep = '\n')
+```
+
+
+
 # Creating premium and contract grids
 
 When developing a new product or comparing different products, it is often