> ## Documentation Index
> Fetch the complete documentation index at: https://validity-kt.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Numbers

> Range, sign, multiples, digits and decimal places of every number type, unsigned included.

The constraints of numbers. The range and sign rules work on every number type, `Int`, `Long`, `Short`, `Byte`,
`Double`, `Float`, `BigInteger` and `BigDecimal`, with an argument of the same type.

> [!NOTE]
>
> A `null` argument checks nothing. A rule that reads a value that may be missing, such as `max(customer.limit)`,
> never fails because of it: `required` on that value reports it once.

```kotlin PriceTag.kt theme={null}
data class PriceTag(
    val price: BigDecimal?,
    val discountPercent: Int?,
    val packSize: Int?,
    val stock: Long?
) : Validatable {
    override fun validation() = validation {
        ::price required {
            positive()
            maxDecimalPlaces(2)
        }
        ::discountPercent required { between(min = 0, max = 90) }
        ::packSize required { multipleOf(6) }
        ::stock required { positiveOrZero() }
    }
}
```

Kotlin's unsigned types, `UInt`, `ULong`, `UShort` and `UByte`, have the range constraints too, with arguments written
with the `u` suffix. They cannot be negative, so they have no sign rules:

```kotlin Packet.kt theme={null}
data class Packet(
    val ttl: UByte?,
    val port: UShort?,
    val sequence: ULong?
) : Validatable {
    override fun validation() = validation {
        ::ttl required { between(min = 1u, max = 64u) }
        ::port required { min(1024u) }
        ::sequence required { min(1uL) }
    }
}
```

| Constraint | Checks |
| - | - |
| [`min`](#min) | Is at least `min`. |
| [`max`](#max) | Is at most `max`. |
| [`greaterThan`](#greaterthan) | Is greater than `other`. |
| [`lessThan`](#lessthan) | Is less than `other`. |
| [`between`](#between) | Is between `min` and `max`, both included. |
| [`positive`](#positive) | Is greater than zero. |
| [`negative`](#negative) | Is less than zero. |
| [`positiveOrZero`](#positiveorzero) | Is zero or greater. |
| [`negativeOrZero`](#negativeorzero) | Is zero or less. |
| [`integer`](#integer) | Has no fractional part. |
| [`multipleOf`](#multipleof) | Is a multiple of `factor`. |
| [`finite`](#finite) | Is neither infinite nor `NaN`. |
| [`minDigits`](#mindigits) | Has at least `min` digits, not counting the sign. |
| [`maxDigits`](#maxdigits) | Has at most `max` digits, not counting the sign. |
| [`digitCount`](#digitcount) | Has exactly `count` digits, not counting the sign. |
| [`maxIntegerDigits`](#maxintegerdigits) | Has at most `max` digits before the decimal point. |
| [`maxDecimalPlaces`](#maxdecimalplaces) | Has at most `max` digits after the decimal point. |
| [`decimalPlaces`](#decimalplaces) | Has exactly `count` digits after the decimal point. |
| [`minDecimalPlaces`](#mindecimalplaces) | Has at least `min` digits after the decimal point. |

## Range

### `min`

`min(min)` on every number type: `Int`, `Long`, `Short`, `Byte`, `Double`, `Float`, `BigInteger`, `BigDecimal`, and the unsigned `UInt`, `ULong`, `UShort`, `UByte`

Checks that the number is at least `min`.

**Code** `min`· **Message** `must be at least {min}` · **Change it** `min = "…"`

### `max`

`max(max)` on every number type: `Int`, `Long`, `Short`, `Byte`, `Double`, `Float`, `BigInteger`, `BigDecimal`, and the unsigned `UInt`, `ULong`, `UShort`, `UByte`

Checks that the number is at most `max`.

**Code** `max`· **Message** `must be at most {max}` · **Change it** `max = "…"`

### `greaterThan`

`greaterThan(other)` on every number type: `Int`, `Long`, `Short`, `Byte`, `Double`, `Float`, `BigInteger`, `BigDecimal`, and the unsigned `UInt`, `ULong`, `UShort`, `UByte`

Checks that the number is greater than `other`.

**Code** `greaterThan`· **Message** `must be greater than {other}` · **Change it** `greaterThan = "…"`

### `lessThan`

`lessThan(other)` on every number type: `Int`, `Long`, `Short`, `Byte`, `Double`, `Float`, `BigInteger`, `BigDecimal`, and the unsigned `UInt`, `ULong`, `UShort`, `UByte`

Checks that the number is less than `other`.

**Code** `lessThan`· **Message** `must be less than {other}` · **Change it** `lessThan = "…"`

### `between`

`between(min, max)` on every number type: `Int`, `Long`, `Short`, `Byte`, `Double`, `Float`, `BigInteger`, `BigDecimal`, and the unsigned `UInt`, `ULong`, `UShort`, `UByte`

Checks that the number is between `min` and `max`, both included.

**Code** `between`· **Message** `must be between {min} and {max}` · **Change it** `between = "…"`

## Sign

### `positive`

`positive()` on every number type: `Int`, `Long`, `Short`, `Byte`, `Double`, `Float`, `BigInteger`, `BigDecimal`

Checks that the number is greater than zero.

**Code** `positive`· **Message** `must be positive` · **Change it** `positive = "…"`

### `negative`

`negative()` on every number type: `Int`, `Long`, `Short`, `Byte`, `Double`, `Float`, `BigInteger`, `BigDecimal`

Checks that the number is less than zero.

**Code** `negative`· **Message** `must be negative` · **Change it** `negative = "…"`

### `positiveOrZero`

`positiveOrZero()` on every number type: `Int`, `Long`, `Short`, `Byte`, `Double`, `Float`, `BigInteger`, `BigDecimal`

Checks that the number is zero or greater.

**Code** `positiveOrZero`· **Message** `must be positive or zero` · **Change it** `positiveOrZero = "…"`

### `negativeOrZero`

`negativeOrZero()` on every number type: `Int`, `Long`, `Short`, `Byte`, `Double`, `Float`, `BigInteger`, `BigDecimal`

Checks that the number is zero or less.

**Code** `negativeOrZero`· **Message** `must be negative or zero` · **Change it** `negativeOrZero = "…"`

## Whole numbers and multiples

### `integer`

`integer()` on `Double`, `Float`, `BigDecimal`

Checks that the number has no fractional part.

Infinity and `NaN` fail.

Trailing zeros do not count, so `2.00` passes.

**Code** `integer`· **Message** `must be an integer` · **Change it** `integer = "…"`

### `multipleOf`

`multipleOf(factor)` on every number type: `Int`, `Long`, `Short`, `Byte`, `BigInteger`, `BigDecimal`, `Double`, `Float`

Checks that the number is a multiple of `factor`.

The remainder is computed in decimal, so `0.3` is a multiple of `0.1`. Infinity and `NaN` fail.

**Code** `multipleOf`· **Message** `must be a multiple of {factor}` · **Change it** `multipleOf = "…"`

### `finite`

`finite()` on `Double`, `Float`

Checks that the number is neither infinite nor `NaN`.

**Code** `finite`· **Message** `must be finite` · **Change it** `finite = "…"`

## Digits

### `minDigits`

`minDigits(min)` on `Int`, `Long`, `Short`, `Byte`, `BigInteger`

Checks that the number has at least `min` digits, not counting the sign.

**Code** `minDigits`· **Message** `must have at least {min} digits` · **Change it** `minDigits = "…"`

### `maxDigits`

`maxDigits(max)` on `Int`, `Long`, `Short`, `Byte`, `BigInteger`

Checks that the number has at most `max` digits, not counting the sign.

**Code** `maxDigits`· **Message** `must have at most {max} digits` · **Change it** `maxDigits = "…"`

### `digitCount`

`digitCount(count)` on `Int`, `Long`, `Short`, `Byte`, `BigInteger`

Checks that the number has exactly `count` digits, not counting the sign.

**Code** `digitCount`· **Message** `must have exactly {count} digits` · **Change it** `digitCount = "…"`

### `maxIntegerDigits`

`maxIntegerDigits(max)` on `BigDecimal`

Checks that the number has at most `max` digits before the decimal point.

**Code** `maxIntegerDigits`· **Message** `must have at most {max} integer digits` · **Change it** `maxIntegerDigits = "…"`

## Decimal places

### `maxDecimalPlaces`

`maxDecimalPlaces(max)` on `BigDecimal`, `Double`, `Float`

Checks that the number has at most `max` digits after the decimal point.

Trailing zeros do not count, so `1.50` has one decimal place. On `Double` and `Float`, the number is read in decimal, the way it prints. Infinity and `NaN` fail.

**Code** `maxDecimalPlaces`· **Message** `must have at most {max} decimal places` · **Change it** `maxDecimalPlaces = "…"`

### `decimalPlaces`

`decimalPlaces(count)` on `BigDecimal`

Checks that the number has exactly `count` digits after the decimal point.

Trailing zeros count, so `1.50` has two decimal places, and a whole number has none.

**Code** `decimalPlaces`· **Message** `must have exactly {count} decimal places` · **Change it** `decimalPlaces = "…"`

### `minDecimalPlaces`

`minDecimalPlaces(min)` on `BigDecimal`

Checks that the number has at least `min` digits after the decimal point.

Trailing zeros count, so `1.50` has two decimal places.

**Code** `minDecimalPlaces`· **Message** `must have at least {min} decimal places` · **Change it** `minDecimalPlaces = "…"`

> [!NOTE]
>
> `Double` and `Float` are binary, so `0.1 + 0.2` is `0.30000000000000004`. `multipleOf` and `maxDecimalPlaces` on them
> read the number in decimal, the way it prints, so `0.3` is a multiple of `0.1`. For money, prefer `BigDecimal`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.