runmat-runtime 0.4.1

Core runtime for RunMat with builtins, BLAS/LAPACK integration, and execution APIs
Documentation
{
  "title": "floor",
  "category": "math/rounding",
  "keywords": [
    "floor",
    "rounding",
    "digits",
    "significant digits",
    "gpu",
    "like"
  ],
  "summary": "Round scalars, vectors, matrices, or N-D tensors toward negative infinity or to specified digits.",
  "references": [],
  "gpu_support": {
    "elementwise": true,
    "reduction": false,
    "precisions": [
      "f32",
      "f64"
    ],
    "broadcasting": "matlab",
    "notes": "Falls back to the host implementation when the active provider lacks unary_floor."
  },
  "fusion": {
    "elementwise": true,
    "reduction": false,
    "max_inputs": 1,
    "constants": "inline"
  },
  "requires_feature": null,
  "tested": {
    "unit": "builtins::math::rounding::floor::tests",
    "integration": "builtins::math::rounding::floor::tests::floor_gpu_provider_roundtrip"
  },
  "description": "`floor(X)` rounds each element of `X` toward negative infinity, returning the greatest integer less than or equal to the input. Optional arguments match MATLAB's extended syntax for rounding to fixed decimal places, significant digits, and prototype-based residency.",
  "behaviors": [
    "Works on scalars, vectors, matrices, and higher-dimensional tensors with MATLAB broadcasting semantics.",
    "`floor(X, N)` rounds toward negative infinity with `N` decimal digits (positive `N`) or powers of ten (negative `N`).",
    "`floor(X, N, 'significant')` rounds to `N` significant digits; `N` must be a positive integer.",
    "Logical inputs are promoted to doubles (`false → 0`, `true → 1`) before flooring.",
    "Character arrays are interpreted numerically (their Unicode code points) and return dense double tensors.",
    "Complex inputs are floored component-wise: `floor(a + bi) = floor(a) + i·floor(b)`.",
    "Non-finite values (`NaN`, `Inf`, `-Inf`) propagate unchanged.",
    "Empty arrays return empty arrays of the appropriate shape.",
    "Appending `'like', prototype` forces the result to match the residency of `prototype` (CPU or GPU). Currently prototypes must be numeric."
  ],
  "examples": [
    {
      "description": "Flooring positive and negative scalars",
      "input": "x = [-2.7, -0.3, 0, 0.8, 3.9];\ny = floor(x)",
      "output": "y = [-3, -1, 0, 0, 3]"
    },
    {
      "description": "Flooring every element of a matrix",
      "input": "A = [1.2 4.7; -3.4 5.0];\nB = floor(A)",
      "output": "B = [1 4; -4 5]"
    },
    {
      "description": "Flooring fractions stored in a tensor",
      "input": "t = reshape([-1.8, -0.2, 0.4, 1.9, 2.1, 3.6], [3, 2]);\nfloored = floor(t)",
      "output": "floored =\n    [-2  1;\n     -1  2;\n      0  3]"
    },
    {
      "description": "Flooring values to a fixed number of decimal places",
      "input": "temps = [21.456 19.995 22.501];\nfloored = floor(temps, 2)",
      "output": "floored = [21.45 19.99 22.50]"
    },
    {
      "description": "Flooring to significant digits",
      "input": "measurements = [0.001234 12.3456 98765];\nsig2 = floor(measurements, 2, 'significant')",
      "output": "sig2 = [0.0012 12.0 98000]"
    },
    {
      "description": "Flooring complex numbers component-wise",
      "input": "z = [1.7 + 2.1i, -0.2 - 3.9i];\nresult = floor(z)",
      "output": "result = [1 + 2i, -1 - 4i]"
    },
    {
      "description": "Keeping GPU data on device when the provider supports `unary_floor`",
      "input": "G = gpuArray([1.8 -0.2 0.0; -1.1 2.5 -3.4]);\nfloored = floor(G);\nH = gather(floored)",
      "output": "H =\n    [ 1 -1  0;\n     -2  2 -4]"
    },
    {
      "description": "Forcing GPU residency with a `'like'` prototype",
      "input": "A = [1.8 -0.2; 2.7 3.4];\nproto = gpuArray(0);\nG = floor(A, 'like', proto);   % Result remains on the GPU\nresult = gather(G)",
      "output": "result =\n    [ 1 -1;\n      2  3]"
    }
  ],
  "faqs": [
    {
      "question": "Does `floor` always round toward negative infinity?",
      "answer": "Yes—positive values round down toward zero, while negative values round to the more negative integer (e.g., `floor(-0.1) = -1`)."
    },
    {
      "question": "How are complex numbers handled?",
      "answer": "The real and imaginary parts are floored independently, matching MATLAB's component-wise definition."
    },
    {
      "question": "Can I round to decimal digits or significant digits?",
      "answer": "Yes. Use `floor(X, N)` for decimal digits or `floor(X, N, 'significant')` for significant digits. Negative `N` values round to powers of ten."
    },
    {
      "question": "What happens with logical arrays?",
      "answer": "Logical values promote to doubles (`0` or `1`) before flooring, so the outputs remain 0 or 1."
    },
    {
      "question": "Can I pass character arrays to `floor`?",
      "answer": "Yes. Character data is treated as its numeric code points, producing a double tensor of the same size."
    },
    {
      "question": "Do `NaN` and `Inf` values change?",
      "answer": "No. Non-finite inputs propagate unchanged."
    },
    {
      "question": "Will GPU execution change floating-point results?",
      "answer": "No. Providers implement IEEE-compliant flooring; when a provider lacks `unary_floor`, RunMat falls back to the CPU to preserve MATLAB-compatible behaviour."
    },
    {
      "question": "Does `'like'` work with `floor`?",
      "answer": "Yes. Append `'like', prototype` to request output that matches the prototype's residency. Currently prototypes must be numeric (scalars or dense tensors, host or GPU)."
    },
    {
      "question": "Can fusion keep `floor` on the GPU?",
      "answer": "Yes. `floor` participates in elementwise fusion, so fused graphs can stay resident on the device when supported."
    },
    {
      "question": "What does floor do in MATLAB?",
      "answer": "`floor(X)` rounds each element of `X` toward negative infinity. For example, `floor(2.7)` returns `2` and `floor(-2.3)` returns `-3`."
    },
    {
      "question": "What is the difference between floor and fix in MATLAB?",
      "answer": "`floor` rounds toward negative infinity, while `fix` rounds toward zero. For positive numbers the result is the same, but for negative numbers they differ: `floor(-2.7)` returns `-3`, while `fix(-2.7)` returns `-2`."
    },
    {
      "question": "Does floor work with GPU arrays in RunMat?",
      "answer": "Yes. RunMat automatically accelerates `floor` on the GPU with elementwise fusion support. Supported precisions include `f32` and `f64` with MATLAB-compatible broadcasting."
    }
  ],
  "links": [
    {
      "label": "ceil",
      "url": "./ceil"
    },
    {
      "label": "round",
      "url": "./round"
    },
    {
      "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/floor.rs`",
    "url": "https://github.com/runmat-org/runmat/blob/main/crates/runmat-runtime/src/builtins/math/rounding/floor.rs"
  },
  "gpu_residency": "```matlab:runnable\nA = [1.8 -0.2; 2.7 3.4];\nproto = gpuArray(0);\nG = floor(A, 'like', proto);   % Result remains on the GPU\nresult = gather(G);\n```\n\nExpected output:\n\n```matlab\nresult =\n    [ 1 -1;\n      2  3]\n```",
  "gpu_behavior": [
    "When tensors already reside on the GPU, RunMat consults the active acceleration provider. If the provider implements the `unary_floor` hook, `floor(X)` executes entirely on the device and keeps tensors resident. When decimal or significant-digit rounding is requested—or when the provider lacks `unary_floor`—RunMat gathers the tensor to host memory, applies the CPU implementation, and honours any `'like'` GPU prototype by uploading the result back to the device. This keeps semantics consistent even when specialised kernels are unavailable."
  ]
}