Functional Weave
Code in TypeScript

agri.feed-ration@1.0.0

README.md

2,012 bytes · view raw

# agri.feed-ration

What a ration costs and how much dry matter it supplies: per head per day,
for the whole group over a period, and per tonne of dry matter. Each feed is
given as fed (fresh weight per head per day), with its dry matter (DM) content
and its price per tonne as fed.

For a dairy cow on 40 kg grass silage (30% DM, £40/t), 15 kg maize silage (32%
DM, £45/t) and 8 kg compound (88% DM, £300/t), the ration is 63 kg fresh,
23.84 kg DM (37.84% DM), 467.5p a day (shown as £4.68), £196.10 per tonne of
DM, and £14,025.00 for 100 cows over 30 days.

## Exactness

Fresh weights are taken to the gram (`math.round-float`), DM is in basis
points and prices are integer minor units per tonne, so every figure is an
exact fraction until it is rounded, once, half up:

- a line's cost is grams x price / 1,000,000; its DM is grams x DM / 10,000;
- the daily cost, the DM intake and the DM % are rounded from the exact sums,
  not added up from the rounded lines;
- the group total is head x days x the exact daily cost, rounded once.
  Multiplying the rounded 468p by 3000 cow-days would overstate it by £15.

Money never goes through a float. Intermediate products are held in `bigint`
(TypeScript), `int` (Python) and `i128` (Rust).

## Conventions

- The price is per tonne **as fed**, as feed merchants quote it. The cost
  per tonne of DM is derived: daily cost / daily DM x 1000.
- DM % of the ration is total DM over total fresh weight; null when nothing
  is fed. The cost per tonne of DM is null when the ration has no DM (water
  only, or no feeds).
- Nothing is added for wastage, shrink or mixing losses; put them in the
  quantity or the price.

It does not balance a ration for energy, protein or minerals, or check
intake against an animal's appetite.

## Limits

Fresh weight 0 to 1000 kg per head per day; DM 0 to 10,000 basis points;
price 0 to 100,000,000 minor units per tonne, in `currency`; head 1 to
1,000,000; days 1 to 3660. A result beyond 2^53 - 1 minor units is refused.