]> Devoid-pointer.net GitWeb - Nine-Q.git/commitdiff
- Print difference between calculated and answered pH instead of trying to rank the...
authorMichal Malý <madcatxster@devoid-pointer.net>
Tue, 23 Dec 2014 02:33:53 +0000 (03:33 +0100)
committerMichal Malý <madcatxster@devoid-pointer.net>
Tue, 23 Dec 2014 02:33:53 +0000 (03:33 +0100)
- Tweaks to the rounding and int/dec/exp splitting
- Fix simplification calculations in acidobazic suite. Generate pKx first and then decide which simplification can be taken into account.

src/formatting_helpers.adb
src/formatting_helpers.ads
src/global_types.adb
src/global_types.ads
src/problem_generators/problem_generator-acidobazic_suite.adb
src/problem_generators/problem_generator-solubility_suite.adb
src/problem_generators/problem_generator.ads

index 182619df7adb05e4bd2e479bebb3897fdb6f40b4..b59049d4017a62a247d6d35528725827ae7012d2 100644 (file)
@@ -22,40 +22,43 @@ package body Formatting_Helpers is
     end;
   end String_To_Float;
  
-  function Round_To_Valid_Nums(Num: in FH_Float; Decimals: in FH_Float) return FH_Float is
+  function Round_To_Valid_Nums(Num: in FH_Float; Decimals: in Natural) return FH_Float is
     package FHEF is new Ada.Numerics.Generic_Elementary_Functions(FH_Float);
     use FHEF;
 
+    ExpDecimals: FH_Float := 10.0 ** Decimals;
     Log_Arg_Floor: FH_Float;
     Temp: FH_Float;
   begin
     Log_Arg_Floor := FH_Float'Floor(Log(Base => 10.0, X => Num));
     Temp := Num / (10.0 ** Log_Arg_Floor);
-    Temp := FH_Float'Rounding(Temp * (Decimals / 10.0));
-    return (Temp / (Decimals / 10.0)) * (10.0 ** Log_Arg_Floor);
+    Temp := FH_Float'Rounding(Temp * ExpDecimals);
+    return (Temp / ExpDecimals) * (10.0 ** Log_Arg_Floor);
   end Round_To_Valid_Nums;
 
-  procedure Split_Integer_Decimal_Unscaled_Strs(Num: in FH_Float; Decimals: in FH_Float; Integer_Part: out UB_Text; Decimal_Part: out UB_Text) is
+  procedure Split_Integer_Decimal_Unscaled_Strs(Num: in FH_Float; Decimals: in Natural; Integer_Part: out UB_Text; Decimal_Part: out UB_Text) is
     Integer_Part_F: FH_Float;
     Decimal_Part_F: FH_Float;
     Decimal_Part_I: Integer;
+    ExpDecimals: constant FH_Float := 10.0 ** Decimals;
   begin
     Integer_Part_F := FH_Float'Floor(Num);
-    Decimal_Part_F := (Num - Integer_Part_F) * Decimals;
+    Decimal_Part_F := (Num - Integer_Part_F) * ExpDecimals;
     Decimal_Part_I := Integer(Decimal_Part_F);
 
     Integer_Part := To_UB_Text(Ada.Strings.Fixed.Trim(Source => Integer'Image(Integer(Integer_Part_F)), Side => Ada.Strings.Left));
     Decimal_Part := To_UB_Text(Ada.Strings.Fixed.Trim(Source => Integer'Image(Decimal_Part_I), Side => Ada.Strings.Left));
-    Prepend_Zeros_To_Text(Decimal_Part_F, Decimals, Decimal_Part);
+    Prepend_Zeros_To_Text(Decimal_Part_F, ExpDecimals, Decimal_Part);
   end Split_Integer_Decimal_Unscaled_Strs;
 
-  procedure Split_Integer_Decimal_Exponent_Nums(Num: in FH_Float; Decimals: in FH_Float; Integer_Part: out Integer; Decimal_Part: out FH_Float; Exponent_Part: out Integer) is
+  procedure Split_Integer_Decimal_Exponent_Nums(Num: in FH_Float; Decimals: in Natural; Integer_Part: out Integer; Decimal_Part: out FH_Float; Exponent_Part: out Integer) is
     package FHEF is new Ada.Numerics.Generic_Elementary_Functions(FH_Float);
     use FHEF;
 
     Expanded: FH_Float;
     Integer_Part_F: FH_Float;
     Log_Arg_Floored: FH_Float;
+    ExpDecimals: constant FH_Float := 10.0 ** Decimals;
   begin
     if Num = 0.0 then 
       Integer_Part := 0;
@@ -68,7 +71,7 @@ package body Formatting_Helpers is
     Expanded := 10.0 ** Log_Arg_Floored;
 
     Integer_Part_F := FH_Float'Floor(Num / Expanded);
-    Decimal_Part := ((Num - (Integer_Part_F * Expanded)) / Expanded) * Decimals;
+    Decimal_Part := ((Num - (Integer_Part_F * Expanded)) / Expanded) * ExpDecimals;
 
     Exponent_Part := Integer(Log_Arg_Floored);
     Integer_Part := Integer(Integer_Part_F);
@@ -76,7 +79,7 @@ package body Formatting_Helpers is
     --Ada.Text_IO.Put_Line(FH_Float'Image(Num) & " --- " & Integer'Image(Integer_Part) & "," & FH_Float'Image(Decimal_Part) & "e" & Integer'Image(Exponent_Part));
   end Split_Integer_Decimal_Exponent_Nums;
 
-  procedure Split_Integer_Decimal_Exponent_Strs(Num: in FH_Float; Decimals: in FH_Float; Integer_Part: out UB_Text; Decimal_Part: out UB_Text;
+  procedure Split_Integer_Decimal_Exponent_Strs(Num: in FH_Float; Decimals: in Natural; Integer_Part: out UB_Text; Decimal_Part: out UB_Text;
                                                Exponent_Part: out UB_Text) is
     package FHEF is new Ada.Numerics.Generic_Elementary_Functions(FH_Float);
     use FHEF;
@@ -85,13 +88,14 @@ package body Formatting_Helpers is
     Decimal_Part_F: FH_Float;
     Decimal_Part_I: Integer;
     Exponent_Part_I: Integer;
+    ExpDecimals: constant FH_Float := 10.0 ** Decimals;
   begin
     Split_Integer_Decimal_Exponent_Nums(Num, Decimals, Integer_Part_I, Decimal_Part_F, Exponent_Part_I);
     Decimal_Part_I := Integer(Decimal_Part_F);
 
     Integer_Part := To_UB_Text(Ada.Strings.Fixed.Trim(Source => Integer'Image(Integer_Part_I), Side => Ada.Strings.Left));
     Decimal_Part := To_UB_Text(Ada.Strings.Fixed.Trim(Source => Integer'Image(Decimal_Part_I), Side => Ada.Strings.Left));
-    Prepend_Zeros_To_Text(Decimal_Part_F, Decimals, Decimal_Part);
+    Prepend_Zeros_To_Text(Decimal_Part_F, ExpDecimals, Decimal_Part);
     Exponent_Part := To_UB_Text(Ada.Strings.Fixed.Trim(Source => Integer'Image(Exponent_Part_I), Side => Ada.Strings.Left));
   end Split_Integer_Decimal_Exponent_Strs;
 
index ad365cba75f98731130d61ed56df8a361d6f4c9d..0f6bb26f712668aa60a173a66fbd40b491227b3b 100644 (file)
@@ -6,11 +6,11 @@ type FH_Float is digits <>;
 package Formatting_Helpers is
 
   function String_To_Float(S: in String) return FH_Float;
-  function Round_To_Valid_Nums(Num: in FH_Float; Decimals: FH_Float) return FH_Float;
-  procedure Split_Integer_Decimal_Unscaled_Strs(Num: in FH_Float; Decimals: in FH_Float; Integer_Part: out UB_Text; Decimal_Part: out UB_Text);
-  procedure Split_Integer_Decimal_Exponent_Nums(Num: in FH_Float; Decimals: in FH_Float; Integer_Part: out Integer; Decimal_Part: out FH_Float;
+  function Round_To_Valid_Nums(Num: in FH_Float; Decimals: Natural) return FH_Float;
+  procedure Split_Integer_Decimal_Unscaled_Strs(Num: in FH_Float; Decimals: in Natural; Integer_Part: out UB_Text; Decimal_Part: out UB_Text);
+  procedure Split_Integer_Decimal_Exponent_Nums(Num: in FH_Float; Decimals: in Natural; Integer_Part: out Integer; Decimal_Part: out FH_Float;
                                                Exponent_Part: out Integer);
-  procedure Split_Integer_Decimal_Exponent_Strs(Num: in FH_Float; Decimals: in FH_Float; Integer_Part: out UB_Text; Decimal_Part: out UB_Text;
+  procedure Split_Integer_Decimal_Exponent_Strs(Num: in FH_Float; Decimals: in Natural; Integer_Part: out UB_Text; Decimal_Part: out UB_Text;
                                                Exponent_Part: out UB_Text);
 
 private
index e4c067c4847a89e6f775b76deea69b0d3f4daf76..1397790bfb917ad40f997761ad92fd6d9e25de44 100644 (file)
@@ -42,6 +42,15 @@ package body Global_Types is
     return To_String(Text);
   end UB_Text_To_Fixed_String;
 
+  -- Overloaded operators
+  function "&" (Left: in UB_Text; Right: in UB_Text) return UB_Text is
+    use Ada.Strings.Unbounded;
+
+    T: UB_Text := Left;
+  begin
+    Append_UB_Text(Source => T, New_Item => Right);
+    return T;
+  end "&";
 
   protected body Simple_Mutex is
     entry Lock when Locked = False is
index 67e93e8228a77e4e5e66cb38b310db0f3adbd8fb..6d6d4b2796517dc45f51b0dba0eca7b87aa027a5 100644 (file)
@@ -17,6 +17,9 @@ package Global_Types is
   function To_UB_Text(S: in String) return UB_Text;
   function UB_Text_To_Fixed_String(Text: in UB_Text) return String;
 
+  -- Overloaded operators
+  function "&" (Left: in UB_Text; Right: in UB_Text) return UB_Text;
+
   protected type Simple_Mutex is
     entry Lock;
     entry Unlock;
index 737436552e472e9247ae9359792fe49d28e7955f..4aa8a877796dcd5318260f97dcf63b8222ddb58e 100644 (file)
@@ -59,28 +59,26 @@ package body Acidobazic_Suite is
     end;
 
     -- Check correctness of the result
-    pH := FH.Round_To_Valid_Nums(pH, Decimals);
-    pH_Answered := FH.Round_To_Valid_Nums(pH_Answered, Decimals);
+    --pH := FH.Round_To_Valid_Nums(pH, Decimals);
+    --pH_Answered := FH.Round_To_Valid_Nums(pH_Answered, Decimals);
+
+    declare
+      pH_Diff: pH_Float := Abs(pH - pH_Answered);
+      pH_Str_Int: UB_Text;
+      pH_Str_Dec: UB_Text;
+      pH_A_Str_Int: UB_Text;
+      pH_A_Str_Dec: UB_Text;
+      pH_Diff_Str_Int: UB_Text;
+      pH_Diff_Str_Dec: UB_Text;
+    begin
+      FH.Split_Integer_Decimal_Unscaled_Strs(pH, DECIMALS, pH_Str_Int, pH_Str_Dec);
+      FH.Split_Integer_Decimal_Unscaled_Strs(pH_Answered, DECIMALS, pH_A_Str_Int, pH_A_Str_Dec);
+      FH.Split_Integer_Decimal_Unscaled_Strs(pH_Diff, DECIMALS, pH_Diff_Str_Int, pH_Diff_Str_Dec);
+
+      Message := To_UB_Text("pH vypočtené programem = ") & pH_Str_Int & To_UB_Text(",") & pH_Str_Dec & To_UB_Text(" - Vaše odpověď = ") & pH_A_Str_Int & To_UB_Text(",") & pH_A_Str_Dec & To_UB_Text(" - (rozdíl = ") & pH_Diff_Str_Int & To_UB_Text(",") & pH_Diff_Str_Dec & To_UB_Text(")");
 
-    if pH_Answered - (Precision * 5.0) < pH and pH_Answered + (Precision * 5.0) > pH then
-      Message := To_UB_Text("Správná odpověď");
       return Correct_Answer;
-    else
-      declare
-       package FH is new Formatting_Helpers(pH_Float);
-
-       Int_S: UB_Text;
-       Dec_S: UB_Text;
-      begin
-       FH.Split_Integer_Decimal_Unscaled_Strs(pH, Decimals, Int_S, Dec_S);
-       Message := To_UB_Text("Nesprávná odpověď. (pH vypočtené programem = ");
-       Append_UB_Text(Source => Message, New_Item => Int_S);
-       Append_UB_Text(Source => Message, New_Item => To_UB_Text(","));
-       Append_UB_Text(Source => Message, New_Item => Dec_S);
-       Append_UB_Text(Source => Message, New_Item => To_UB_Text(")"));
-       return Wrong_Answer;
-      end;
-    end if;
+    end;
   end Check_Answer;
 
   function Get_Assignment(Problem: in out Acidobazic_Problem; Assignment: in out Assignment_Info.Map; Resource_Prefix: in String) return RetCode is
@@ -152,46 +150,19 @@ package body Acidobazic_Suite is
 
   procedure New_Problem(Problem: in out Acidobazic_Problem) is
     package Random_Substance_Type_Gen is new Ada.Numerics.Discrete_Random(Result_Subtype => Substance_Type);
-    package Random_Dissoc_Type_Gen is new Ada.Numerics.Discrete_Random(Result_Subtype => Dissociation_Constant_Type);
 
-    DCT_G: Random_Dissoc_Type_Gen.Generator;
     ST_G: Random_Substance_Type_Gen.Generator;
 
     cX_Min: pH_Float;
     cX_Max: pH_Float;
   begin
-    -- Dissociation constant type (pKa or pKb)
-    Random_Dissoc_Type_Gen.Reset(Gen => DCT_G);
-    Problem.DCT := Random_Dissoc_Type_Gen.Random(Gen => DCT_G);
-
     -- Substance type (acid or base)
     Random_Substance_Type_Gen.Reset(Gen => ST_G);
     Problem.Subst_Type := Random_Substance_Type_Gen.Random(Gen => ST_G);
+    -- Get random dissociation constant
+    Problem.Kx := Random_Kx;
     -- What simplification to use
-    if Problem.Parameters.No_Both_Simplifications = False then
-      declare
-       package Random_Simplification_Gen is new Ada.Numerics.Discrete_Random(Result_Subtype => Simplification);
-       SIM_G: Random_Simplification_Gen.Generator;
-      begin
-       Random_Simplification_Gen.Reset(Gen => SIM_G);
-       Problem.Simpl := Random_Simplification_Gen.Random(Gen => SIM_G);
-
-       -- Random dissociation constant
-       Problem.Kx := Random_Kx;
-      end;
-    else
-      declare
-       subtype Enforced_Simplification is Simplification range Autoprotolysis .. Dissociation;
-       package Random_Simplification_Gen is new Ada.Numerics.Discrete_Random(Result_Subtype => Enforced_Simplification);
-       SIM_G: Random_Simplification_Gen.Generator;
-      begin
-       Random_Simplification_Gen.Reset(Gen => SIM_G);
-       Problem.Simpl := Random_Simplification_Gen.Random(Gen => SIM_G);
-
-       Problem.Kx := Random_Kx_Enforced(Problem.Simpl);
-       -- Generate dissociation constant that fits the enforced simplification mode 
-      end;
-    end if;
+    Problem.Simpl := Random_Simplification(Problem.Kx, Problem.Parameters.No_Both_Simplifications);
 
     Calculate_Concentration_Limits(cX_Min, cX_Max, Problem.Kx, Problem.Simpl);
     Problem.cX := Random_cX(cX_Min, cX_Max);
@@ -265,13 +236,13 @@ package body Acidobazic_Suite is
       -- We are ignoring everything
       when Both =>
        declare
-         pH: constant pH_Float := X_To_pX(Sqrt(Problem.Kx * Problem.cX));
+         pX: constant pH_Float := X_To_pX((Problem.Kx * Problem.cX) ** 0.5);
        begin
          case Problem.Subst_Type is
            when Acid =>
-             return pH;
+             return pX;
          when Base =>
-           return 14.0 - pH;
+           return 14.0 - pX;
          end case;
        end;
       -- We are ignoring autoprotolysis and taking dissociation into account
@@ -280,33 +251,33 @@ package body Acidobazic_Suite is
          D: pH_Float;
          X_1: pH_Float;
          X_2: pH_Float;
-         pH: pH_Float;
+         pX: pH_Float;
        begin
          -- Solve the quadratic equation
          D := (Problem.Kx ** 2.0) + (4.0 * Problem.Kx * Problem.cX);
          if D < 0.0 then
            raise Constraint_Error;
          end if;
-         D := MEF.Sqrt(D);
+         D := D ** 0.5;
          X_1 := (-Problem.Kx + D) / 2.0;
          X_2 := (-Problem.Kx - D) / 2.0;
-         pH := X_To_pX(pH_Float'Max(X_1, X_2));
+         pX := X_To_pX(pH_Float'Max(X_1, X_2));
          if Problem.Subst_Type = Base then
-           return 14.0 - pH;
+           return 14.0 - pX;
          else
-           return pH;
+           return pX;
          end if;
        end;
        -- We are ignoring dissociation and taking autoprotolysis into account
       when Dissociation =>
        declare
-         pH: constant pH_Float := X_To_pX(Sqrt(Problem.Kx * Problem.cX + K_W));
+         pX: constant pH_Float := X_To_pX((Problem.Kx * Problem.cX + K_W) ** 0.5);
        begin
          case Problem.Subst_Type is
            when Acid =>
-             return pH;
+             return pX;
            when Base =>
-             return 14.0 - pH;
+             return 14.0 - pX;
          end case;
        end;
     end case;
@@ -336,7 +307,7 @@ package body Acidobazic_Suite is
     use MEF;
 
     F_Log_Num: constant pH_Float := pH_Float'Floor(Log(Base => 10.0, X => Num));
-    F_Log_Dec: constant pH_Float := pH_Float'Floor(Log(Base => 10.0, X => Decimals));
+    F_Log_Dec: constant pH_Float := pH_Float'Floor(Log(Base => 10.0, X => pH_Float(DECIMALS)));
   begin
     return F_Log_Num - F_Log_Dec;
   end Correction_Exponent;
@@ -409,43 +380,40 @@ package body Acidobazic_Suite is
     return pX_To_X(pKx);
   end Random_Kx;
 
-  function Random_Kx_Enforced(S: in Simplification) return pH_Float is
-    package FH is new Formatting_Helpers(pH_Float);
-    use Ada.Numerics.Float_Random;
-
-    Seed: Generator;
-    Rand: Float;
-    pH_Rand: pH_Float;
-    pKx: pH_Float;
+  function Random_Simplification(Kx: in pH_Float; No_Both_Simplifications: in Boolean) return Simplification is
+    package Random_Simplification_Gen is new Ada.Numerics.Discrete_Random(Result_Subtype => Boolean);
+    SIM_G: Random_Simplification_Gen.Generator;
+    B: Boolean;
+    pKx: constant pH_Float := X_To_pX(Kx);
   begin
-    Reset(Seed);
-    Rand := Random(Seed);
-    pH_Rand := pH_Float(Rand);
-
-    case S is
-      -- Ignore autoprotolysis, enforce dissociation
-      when Autoprotolysis =>
-       declare
-         Scale: constant pH_Float := Acidic_Max_pH - Acidic_Min_pH;
-       begin
-         -- pKa and pKb between <2.0; 7.5> can overpower autoprotolysis and might require dissociation
-         pKx := (Scale * pH_Rand) + Acidic_Min_pH;
-       end;
-      -- Ignore dissociation, enforce autoprotolysis
-      when Dissociation =>
-       -- pKa and pKb between <7.6; 12> do not require dissociation but might require autoprotolysis
-       declare
-         Scale: constant pH_Float := Basic_Max_pH - Basic_Min_pH;
-       begin
-         pKx := (Scale * pH_Rand) + Basic_Min_pH;
-       end;
-      when others =>
-       raise Constraint_Error;
-    end case;
-
-    pKx := FH.Round_To_Valid_Nums(pKx, Decimals);
-    return pX_To_X(pKx);
-  end Random_Kx_Enforced;
+    if pKx <= Acidic_Max_pH then
+      if No_Both_Simplifications then
+       return Autoprotolysis; -- Ignore autoprotolysis, take dissociation into account
+      else
+       Random_Simplification_Gen.Reset(Gen => SIM_G);
+       B := Random_Simplification_Gen.Random(Gen => SIM_G);
+       if B then
+         return Autoprotolysis; -- Ignore autoprotolysis, take dissociation into account
+       else
+         return Both; -- Ignore everything
+       end if;
+      end if;
+    elsif pKx >= Basic_Min_pH then
+      if No_Both_Simplifications then
+       return Dissociation; -- Ignore dissociation, take autoprotolysis into account
+      else
+       Random_Simplification_Gen.Reset(Gen => SIM_G);
+       B := Random_Simplification_Gen.Random(Gen => SIM_G);
+       if B then
+         return Dissociation; -- Ignore dissociation, take autoprotolysis into account
+       else
+         return Both; -- Ignore everything
+       end if;
+      end if;
+    else
+      raise Constraint_Error;
+    end if;
+  end Random_Simplification;
 
   function X_To_pX(X: in pH_Float) return pH_Float is
     package MEF is new Ada.Numerics.Generic_Elementary_Functions(pH_Float);
index db05b0fb747868f4b0939ec3af815e17d0a9ecc5..336fe2fdb6e468b6ac453df532e8d8a086985a59 100644 (file)
@@ -229,7 +229,7 @@ package body Solubility_Suite is
          G := Round_To_Valid_Nums(G, DECIMALS);
          Ks := Round_To_Valid_Nums(Generate_Solubility_Product, DECIMALS);
          MW := (SS_Float(Random(Gen => Float_RGen)) * MOLAR_WEIGHT_RANGE) + MOLAR_WEIGHT_MIN;
-         MW := SS_Float'Rounding(MW * DECIMALS_MW) / DECIMALS_MW;
+         MW := SS_Float'Rounding(MW * SS_Float(DECIMALS_MW)) / SS_Float(DECIMALS_MW);
          Prob_Data := (Option => V_FROM_G_KS,
                        M => SS_Float(M), N => SS_Float(N),
                        V_G => G, V_Ks => Ks, V_MW => MW);
@@ -246,7 +246,7 @@ package body Solubility_Suite is
          G := (SS_Float(Random(Gen => Float_RGen)) * SAMPLE_WEIGHT_RANGE) + SAMPLE_WEIGHT_MIN;
          G := Round_To_Valid_Nums(G, DECIMALS);
          MW := (SS_Float(Random(Gen => Float_RGen)) * MOLAR_WEIGHT_RANGE) + MOLAR_WEIGHT_MIN;
-         MW := SS_Float'Rounding(MW * DECIMALS_MW) / DECIMALS_MW;
+         MW := SS_Float'Rounding(MW * SS_Float(DECIMALS_MW)) / SS_Float(DECIMALS_MW);
          V := Round_To_Valid_Nums(Generate_Sample_Volume, DECIMALS);
          Prob_Data := (Option => KS_FROM_G_V,
                        M => SS_Float(M), N => SS_Float(N),
index 78a4655e2e97c1f7933b82d25bc219b7f74e6e11..9f15b76e8bb4d53cc6740e18c4f3d45742aaa301 100644 (file)
@@ -58,14 +58,13 @@ private
       function pX_To_X(pX: in pH_Float) return pH_Float;
       function Random_cX(Min: in pH_Float; Max: in pH_Float) return pH_Float;
       function Random_Kx return pH_Float;
-      function Random_Kx_Enforced(S: in Simplification) return pH_Float;
+      function Random_Simplification(Kx: in pH_Float; No_Both_Simplifications: in Boolean) return Simplification;
       function X_To_pX(X: in pH_Float) return pH_Float;
 
       type Acidobazic_Problem is new Problem_Generator.Chem_Problem with
        record
          Answer: pH_Float;
          cX: pH_Float;
-         DCT: Dissociation_Constant_Type;
          Kx: pH_Float;
          Parameters: Acidobazic_Parameters;
          Simpl: Simplification;
@@ -80,8 +79,7 @@ private
       -- Maximum concentration can be only 1.5 mol/dm3 higher than minimum concentration
       MAX_CONCENTRATION_DIFF: constant pH_Float := 0.75;
       CONCENTRATION_HARD_MIN_LIMIT: constant pH_Float := 1.0E-6;
-      Decimals: constant pH_Float := 1.0E3;
-      Precision: constant pH_Float := 1.0E-3;
+      DECIMALS: constant Natural := 3;
 
   end Acidobazic_Suite;
 
@@ -112,8 +110,8 @@ private
     SAMPLE_VOLUME_LOG_MIN: constant SS_Float := -0.3;
     SAMPLE_WEIGHT_MAX: constant SS_Float := 1.5;
     SAMPLE_WEIGHT_MIN: constant SS_Float := 0.1;
-    DECIMALS: constant SS_Float := 1.0E3;
-    DECIMALS_MW: constant SS_Float := 1.0E2;
+    DECIMALS: constant Natural := 3;
+    DECIMALS_MW: constant Natural := 2;
     PRECISION: constant SS_Float := 1.0E2;
 
     type Ion is
@@ -228,7 +226,7 @@ private
     TITR_BASE_KB: constant T_Float := 0.0001; -- Corresponds to NaOH
     KW: constant T_Float := 1.0E-14;
     --
-    DECIMALS: constant T_Float := 1.0E3;
+    DECIMALS: constant Natural := 3;
     MAX_DIFFERENCE: constant := 3.0E-14;
     --
     IMAGE_WIDTH: constant Glib.GInt := 800;