## arithmetic/src/basictypes/physicalunit/PhysicalValue.mg

```GENERIC MODULE PhysicalValue(R);
```
Arithmetic for Modula-3, see doc for details
```
IMPORT PhysicalUnit AS U;

IMPORT Arithmetic AS Arith;

<* UNUSED *>
CONST
Module = "PhysicalValue.";

BEGIN
(* if the value is zero, different units don't matter*)
IF R.IsZero(y.val) THEN
RETURN x;
ELSIF R.IsZero(x.val) THEN
RETURN y;
ELSE
IF NOT U.Equal(x.unit, y.unit) THEN
RAISE Arith.Error(NEW(Arith.ErrorUnitMismatch).init());
END;
END;

PROCEDURE Sub (READONLY x, y: T; ): T RAISES {Arith.Error} =
BEGIN
(* if the value is zero, different units don't matter*)
IF R.IsZero(y.val) THEN
RETURN x;
ELSIF R.IsZero(x.val) THEN
RETURN Neg(y);
ELSE
IF NOT U.Equal(x.unit, y.unit) THEN
RAISE Arith.Error(NEW(Arith.ErrorUnitMismatch).init());
END;
RETURN T{R.Sub(x.val, y.val), x.unit};
END;
END Sub;

PROCEDURE Neg (READONLY x: T; ): T =
BEGIN
RETURN T{R.Neg(x.val), x.unit};
END Neg;

PROCEDURE Conj (READONLY x: T; ): T =
BEGIN
RETURN T{R.Conj(x.val), x.unit};
END Conj;

PROCEDURE IsZero (READONLY x: T; ): BOOLEAN =
BEGIN
RETURN R.IsZero(x.val);
END IsZero;

PROCEDURE IsScalar (READONLY x: T; ): BOOLEAN =
BEGIN
RETURN U.IsZero(x.unit) OR R.IsZero(x.val);
END IsScalar;

PROCEDURE Equal (READONLY x, y: T; ): BOOLEAN =
BEGIN
RETURN R.Equal(x.val, y.val) AND U.Equal(x.unit, y.unit);
END Equal;

PROCEDURE Mul (READONLY x, y: T; ): T =
BEGIN
END Mul;

PROCEDURE Div (READONLY x, y: T; ): T RAISES {Arith.Error} =
BEGIN
RETURN T{R.Div(x.val, y.val), U.Sub(x.unit, y.unit)};
END Div;

PROCEDURE Rec (READONLY x: T; ): T RAISES {Arith.Error} =
BEGIN
RETURN T{R.Rec(x.val), U.Neg(x.unit)};
END Rec;

PROCEDURE Mod (READONLY x, y: T; ): T RAISES {Arith.Error} =
BEGIN
RETURN T{R.Mod(x.val, y.val), x.unit};
END Mod;

PROCEDURE DivMod (READONLY x, y: T; ): QuotRem RAISES {Arith.Error} =
VAR qr := R.DivMod(x.val, y.val);
BEGIN
RETURN QuotRem{T{qr.quot, U.Sub(x.unit, y.unit)}, T{qr.rem, x.unit}};
END DivMod;

PROCEDURE Square (READONLY x: T; ): T =
BEGIN
(* RETURN T{R.Square(x.val),U.Scale(x.unit,2)}; *)
RETURN T{R.Mul(x.val, x.val), U.Scale(x.unit, 2)};
END Square;

PROCEDURE Scale (READONLY x: T; y: R.T; ): T =
BEGIN
RETURN T{R.Mul(x.val, y), x.unit};
END Scale;

BEGIN
Zero := T{val := R.Zero, unit := U.New()};
One := T{val := R.One, unit := Zero.unit};
END PhysicalValue.
```
```

```