runmat-runtime 0.4.5

Core runtime for RunMat with builtins, BLAS/LAPACK integration, and execution APIs
Documentation
{
  "title": "round",
  "category": "math/rounding",
  "keywords": [
    "round",
    "rounding",
    "significant digits",
    "decimals",
    "gpu"
  ],
  "summary": "Round scalars, vectors, matrices, or N-D tensors to the nearest integers, decimal digits, or significant digits.",
  "references": [],
  "gpu_support": {
    "elementwise": true,
    "reduction": false,
    "precisions": [
      "f32",
      "f64"
    ],
    "broadcasting": "matlab",
    "notes": "Falls back to the host implementation when rounding to digits or significant figures if the active provider lacks unary_round."
  },
  "fusion": {
    "elementwise": true,
    "reduction": false,
    "max_inputs": 1,
    "constants": "inline"
  },
  "requires_feature": null,
  "tested": {
    "unit": "builtins::math::rounding::round::tests",
    "integration": "builtins::math::rounding::round::tests::round_gpu_provider_roundtrip"
  },
  "description": "`round(X)` rounds numeric values to the nearest integers using MATLAB-compatible half-away-from-zero semantics. Additional arguments allow rounding to a specified number of decimal digits or significant digits.",
  "behaviors": [
    "`round(X)` rounds each element of `X` to the nearest integer; ties (e.g., `±0.5`) round away from zero.",
    "`round(X, N)` rounds to `N` decimal digits when `N` is positive and to powers of ten when `N` is negative.",
    "`round(X, N, 'significant')` rounds to `N` significant digits. `N` must be a positive integer.",
    "Logical inputs are promoted to double before rounding; `round(true)` returns `1`.",
    "Complex inputs are rounded component-wise (`round(a + bi) = round(a) + i·round(b)`), matching MATLAB.",
    "Non-finite values (`NaN`, `Inf`, `-Inf`) propagate unchanged regardless of precision arguments.",
    "Character arrays are treated as their numeric code points and return double tensors of the same size."
  ],
  "examples": [
    {
      "description": "Rounding values to the nearest integers",
      "input": "X = [-3.5 -2.2 -0.5 0 0.5 1.7];\nY = round(X)",
      "output": "Y = [-4 -2 -1 0 1 2]"
    },
    {
      "description": "Rounding to a fixed number of decimal places",
      "input": "temps = [21.456 19.995 22.501];\nrounded = round(temps, 2)",
      "output": "rounded = [21.46 20.00 22.50]"
    },
    {
      "description": "Rounding to negative powers of ten",
      "input": "counts = [1234 5678 91011];\nrounded = round(counts, -2)",
      "output": "rounded = [1200 5700 91000]"
    },
    {
      "description": "Rounding to significant digits",
      "input": "measurements = [0.001234 12.3456 98765];\nsig3 = round(measurements, 3, 'significant')",
      "output": "sig3 = [0.00123 12.3 98800]"
    },
    {
      "description": "Rounding GPU tensors and gathering the results",
      "input": "G = gpuArray(linspace(-2.5, 2.5, 6));\nrounded = round(G);\nhostValues = gather(rounded)",
      "output": "hostValues = [-3 -2 -1 1 2 3]"
    }
  ],
  "faqs": [
    {
      "question": "Does `round` always round half values away from zero?",
      "answer": "Yes. MATLAB and RunMat both use half-away-from-zero semantics, so `round(0.5)` returns `1` and `round(-0.5)` returns `-1`."
    },
    {
      "question": "Can I round to decimal places and significant digits?",
      "answer": "Yes. Use `round(X, N)` for decimal places and `round(X, N, 'significant')` for significant digits. Negative `N` values round to tens, hundreds, and so on."
    },
    {
      "question": "What happens if I pass a non-integer `N`?",
      "answer": "`N` must be an integer scalar. RunMat raises a MATLAB-compatible error when `N` is not an integer or is non-finite."
    },
    {
      "question": "How are complex numbers handled?",
      "answer": "RunMat rounds the real and imaginary components independently, matching MATLAB's component-wise behaviour."
    },
    {
      "question": "Do NaN or Inf values change when rounded?",
      "answer": "No. Non-finite values propagate unchanged for every rounding mode, just like MATLAB."
    },
    {
      "question": "Will rounding stay on the GPU?",
      "answer": "`round(X)` stays on the GPU when the provider implements `unary_round`. Rounding with digit arguments currently gathers to the host; providers can override this by adding specialised kernels."
    },
    {
      "question": "Can I round logical or character arrays?",
      "answer": "Yes. Logical values are converted to doubles (`0` or `1`) and characters are rounded as their numeric code points, returning dense double tensors."
    },
    {
      "question": "What does round do in MATLAB?",
      "answer": "`round(X)` rounds each element of `X` to the nearest integer. `round(X, N)` rounds to `N` decimal places. Ties (e.g., 2.5) round away from zero."
    },
    {
      "question": "What is the difference between round, floor, and ceil in MATLAB?",
      "answer": "`round` rounds to the nearest integer, `floor` rounds toward negative infinity, and `ceil` rounds toward positive infinity. For 2.5: `round` returns 3, `floor` returns 2, `ceil` returns 3."
    },
    {
      "question": "Does round support GPU acceleration in RunMat?",
      "answer": "Yes. `round` runs on the GPU with elementwise fusion support. It accepts `f32` and `f64` precisions and supports MATLAB-compatible broadcasting."
    },
    {
      "question": "Does MATLAB's `round` use banker's rounding?",
      "answer": "— **No.** MATLAB (and RunMat) round halves *away from zero*, not to even. So `round(0.5)` returns `1`, `round(-0.5)` returns `-1`, `round(2.5)` returns `3`, and `round(3.5)` returns `4`. This differs from Python's built-in `round` and IEEE 754 default rounding, which both use banker's rounding (round-half-to-even). NumPy's `np.round` also uses banker's rounding, so ported code may give different results on `.5` cases — use `round(x)` in MATLAB/RunMat when you specifically want half-away-from-zero."
    },
    {
      "question": "How do I round to N decimal places?",
      "answer": "— Use `round(X, N)`. Positive `N` rounds to digits to the right of the decimal point; negative `N` rounds to digits to the left. For example, `round(pi, 3)` returns `3.1416` and `round(12345, -3)` returns `12000`. Use `round(X, N, 'significant')` when you want `N` significant digits instead of decimal places."
    }
  ],
  "links": [
    {
      "label": "floor",
      "url": "./floor"
    },
    {
      "label": "ceil",
      "url": "./ceil"
    },
    {
      "label": "fix",
      "url": "./fix"
    },
    {
      "label": "gpuArray",
      "url": "./gpuarray"
    },
    {
      "label": "gather",
      "url": "./gather"
    },
    {
      "label": "mod",
      "url": "./mod"
    },
    {
      "label": "rem",
      "url": "./rem"
    }
  ],
  "source": {
    "label": "`crates/runmat-runtime/src/builtins/math/rounding/round.rs`",
    "url": "https://github.com/runmat-org/runmat/blob/main/crates/runmat-runtime/src/builtins/math/rounding/round.rs"
  },
  "gpu_residency": "You usually do **not** need to call `gpuArray` manually. RunMat's planner keeps tensors on the GPU when the provider exposes the required kernels and it is profitable to do so. `round` takes advantage of this mechanism for the plain `round(X)` form. When you specify digits or the `'significant'` option, RunMat currently gathers data to the host to match MATLAB exactly. Future providers can extend `unary_round` or add digit-aware kernels to keep those workloads on the device.",
  "gpu_behavior": [
    "When a tensor already resides on the GPU, RunMat checks whether the active acceleration provider implements a specialised `unary_round` kernel. If available, `round(X)` executes entirely on the device. Advanced modes (`round(X, N)` and `round(X, N, 'significant')`) currently gather tensors to the host before rounding to keep semantics aligned with MATLAB. Providers that add digit-aware kernels can extend this path in the future."
  ],
  "syntax": {
    "example": {
      "description": "Syntax",
      "input": "Y = round(X)\nY = round(X, N)\nY = round(X, N, type)"
    },
    "points": [
      "`X` is the numeric (or `duration`) input to round. Scalars, vectors, matrices, and N-D arrays are all accepted. Complex values are rounded component-wise; non-finite values (`NaN`, `Inf`) pass through unchanged.",
      "`N` is an integer specifying the number of digits. When `type` is `'decimals'` (the default), positive `N` rounds to digits right of the decimal point and negative `N` rounds to digits left of it (tens, hundreds, thousands, ...). When `type` is `'significant'`, `N` must be a positive integer.",
      "`type` is an optional string: `'decimals'` (default) or `'significant'`. `'significant'` rounds to `N` significant digits regardless of magnitude.",
      "Returns `Y`, the rounded values, same shape and (promoted) class as `X`. Half values are rounded away from zero — MATLAB's `round` does **not** use banker's rounding."
    ]
  }
}