Functional Weave
Code in Rust

agri.seed-rate@1.0.0

impl/typescript.ts

1,763 bytes · the TypeScript implementation · view raw

Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.

import { roundDiv } from "./math_round_div.ts";  ← from math.round-div ^1.0.0 · built alongside by fune
import { roundFloat } from "./math_round_float.ts";  ← from math.round-float ^1.0.0 · built alongside by fune
import { type SeedRate } from "./agri_seed_rate_types.ts";

/**
 * Seed rate (kg/ha) = target plants/m² x TGW (g) / expected establishment (%).
 *
 * The TGW is taken to the centigram and the establishment is in basis points,
 * so kg/ha is exactly plants x centigrams / basis points and is rounded once.
 * Doing it in floats gets 100 x 1.15 / 100 = 1.1499999999999999, which rounds
 * to 1.1 kg/ha instead of 1.2.
 */
export function seedRate(targetPlantsPerSquareMetre: number, thousandGrainWeightGrams: number, establishmentBasisPoints: number): SeedRate {
  const plants = targetPlantsPerSquareMetre;
  if (typeof plants !== "number" || !Number.isInteger(plants) || plants < 1 || plants > 100000) {
    throw new RangeError(`targetPlantsPerSquareMetre must be a whole number from 1 to 100000, received ${plants}`);
  }
  const tgw = thousandGrainWeightGrams;
  if (typeof tgw !== "number" || !Number.isFinite(tgw) || tgw <= 0 || tgw > 1000) {
    throw new RangeError(`thousandGrainWeightGrams must be a finite number greater than 0 and at most 1000, received ${tgw}`);
  }
  const centigrams = Math.round(roundFloat(tgw, 2) * 100);
  if (centigrams < 1) {
    throw new RangeError(`thousandGrainWeightGrams must be at least 0.01 grams, received ${tgw}`);
  }
  const bp = establishmentBasisPoints;
  if (typeof bp !== "number" || !Number.isInteger(bp) || bp < 1 || bp > 10000) {
    throw new RangeError(`establishmentBasisPoints must be a whole number from 1 to 10000, received ${bp}`);
  }
  return {
    kgPerHectare: roundDiv(plants * centigrams * 10, bp, "half-up") / 10,
    seedsPerSquareMetre: roundDiv(plants * 100000, bp, "half-up") / 10,
  };
}