Struct DataUnit
Encapsulates a data size, stored internally in bytes, and provides properties that allow for conversions and interactions between multiple standard and binary data size units.
Implements
Inherited Members
Namespace: Scylla.Core.Util.Units
Assembly: ScyllaCore.dll
Syntax
public struct DataUnit : IEquatable<DataUnit>
Remarks
DataUnit uses double precision throughout, which is sufficient for
representing sizes from single bits up to quettabytes (10^30 bytes) without loss of
practical accuracy.
Two sets of unit prefixes are supported:
- SI (decimal, powers of 1000): kB, MB, GB, TB, PB, EB, ZB, YB, RB, QB, and their bit equivalents (kb, Mb, Gb, etc.).
- IEC (binary, powers of 1024): KiB, MiB, GiB, TiB, PiB, EiB, ZiB, YiB.
All values must be non-negative. Setting any property to a negative, infinite, or NaN
value will throw an ArgumentOutOfRangeException via
NumberUtil.EnsureFiniteNonNegative.
Equality comparisons use NumberUtil.Approximately to guard against floating-point
rounding artifacts when converting between units. Ordering operators use exact
byte-level comparison.
The ToString() override automatically selects the most human-readable SI byte unit for the stored value, falling back to bits and nibbles for sub-byte quantities.
var size = new DataUnit();
size.Megabyte = 1.5;
Console.WriteLine(size.Kilobyte); // 1500
Console.WriteLine(size.Mebibyte); // ~1.43 (binary conversion)
Console.WriteLine(size); // "1.5 MB"
var a = new DataUnit { Gigabyte = 2 };
var b = new DataUnit { Gigabyte = 1 };
var c = a - b; // 1 GB
var ratio = a / b; // 2.0
Constructors
DataUnit(double)
Initializes a new DataUnit instance with the given size in bytes.
Declaration
public DataUnit(double bytes = 0)
Parameters
| Type | Name | Description |
|---|---|---|
| double | bytes | The initial data size in bytes. Must be finite and non-negative.
Defaults to |
Exceptions
| Type | Condition |
|---|---|
| ArgumentOutOfRangeException | Thrown if |
Properties
Bit
Gets or sets the data size expressed in bits, where 8 bits equal one byte. Setting this property converts the given bit count to an equivalent byte value and stores it internally. The value must be finite and non-negative.
Declaration
public double Bit { get; set; }
Property Value
| Type | Description |
|---|---|
| double |
Exceptions
| Type | Condition |
|---|---|
| ArgumentOutOfRangeException | Thrown by the setter if the assigned value is negative, NaN, or infinite. |
Byte
Gets or sets the data size expressed in bytes, which is the canonical internal storage unit for DataUnit. Reading this property returns the raw stored value without conversion. Setting it validates and stores the new byte count directly. The value must be finite and non-negative.
Declaration
public double Byte { get; set; }
Property Value
| Type | Description |
|---|---|
| double |
Exceptions
| Type | Condition |
|---|---|
| ArgumentOutOfRangeException | Thrown by the setter if the assigned value is negative, NaN, or infinite. |
Exabit
Gets or sets the data size expressed in exabits (Eb) using the SI decimal convention, where 1 Eb = 1000^6 bits.
Declaration
public double Exabit { get; set; }
Property Value
| Type | Description |
|---|---|
| double |
Exceptions
| Type | Condition |
|---|---|
| ArgumentOutOfRangeException | Thrown by the setter if the assigned value is negative, NaN, or infinite. |
Exabyte
Gets or sets the data size expressed in exabytes (EB) using the SI decimal convention, where 1 EB = 1000^6 bytes. For the binary equivalent, use Exbibyte instead.
Declaration
public double Exabyte { get; set; }
Property Value
| Type | Description |
|---|---|
| double |
Exceptions
| Type | Condition |
|---|---|
| ArgumentOutOfRangeException | Thrown by the setter if the assigned value is negative, NaN, or infinite. |
Exbibyte
Gets or sets the data size expressed in exbibytes (EiB) using the IEC binary convention, where 1 EiB = 1024^6 bytes. For the SI decimal equivalent, use Exabyte instead.
Declaration
public double Exbibyte { get; set; }
Property Value
| Type | Description |
|---|---|
| double |
Exceptions
| Type | Condition |
|---|---|
| ArgumentOutOfRangeException | Thrown by the setter if the assigned value is negative, NaN, or infinite. |
Gibibyte
Gets or sets the data size expressed in gibibytes (GiB) using the IEC binary convention, where 1 GiB = 1024^3 bytes (1,073,741,824 bytes). For the SI decimal equivalent, use Gigabyte instead.
Declaration
public double Gibibyte { get; set; }
Property Value
| Type | Description |
|---|---|
| double |
Exceptions
| Type | Condition |
|---|---|
| ArgumentOutOfRangeException | Thrown by the setter if the assigned value is negative, NaN, or infinite. |
Gigabit
Gets or sets the data size expressed in gigabits (Gb) using the SI decimal convention, where 1 Gb = 1,000,000,000 bits (1000^3).
Declaration
public double Gigabit { get; set; }
Property Value
| Type | Description |
|---|---|
| double |
Exceptions
| Type | Condition |
|---|---|
| ArgumentOutOfRangeException | Thrown by the setter if the assigned value is negative, NaN, or infinite. |
Gigabyte
Gets or sets the data size expressed in gigabytes (GB) using the SI decimal convention, where 1 GB = 1,000,000,000 bytes (1000^3). For the binary equivalent, use Gibibyte instead.
Declaration
public double Gigabyte { get; set; }
Property Value
| Type | Description |
|---|---|
| double |
Exceptions
| Type | Condition |
|---|---|
| ArgumentOutOfRangeException | Thrown by the setter if the assigned value is negative, NaN, or infinite. |
Kibibyte
Gets or sets the data size expressed in kibibytes (KiB) using the IEC binary convention, where 1 KiB = 1024 bytes (2^10). Use this property when working with memory sizes or file-system allocations that follow powers-of-1024 counting. For the SI decimal equivalent, use Kilobyte instead.
Declaration
public double Kibibyte { get; set; }
Property Value
| Type | Description |
|---|---|
| double |
Exceptions
| Type | Condition |
|---|---|
| ArgumentOutOfRangeException | Thrown by the setter if the assigned value is negative, NaN, or infinite. |
Kilobit
Gets or sets the data size expressed in kilobits (kb) using the SI decimal convention, where 1 kb = 1,000 bits. Kilobits are commonly used for expressing network transfer speeds (e.g., 100 kb/s).
Declaration
public double Kilobit { get; set; }
Property Value
| Type | Description |
|---|---|
| double |
Exceptions
| Type | Condition |
|---|---|
| ArgumentOutOfRangeException | Thrown by the setter if the assigned value is negative, NaN, or infinite. |
Kilobyte
Gets or sets the data size expressed in kilobytes (kB) using the SI decimal convention, where 1 kB = 1,000 bytes. For the binary equivalent using powers of 1024, use Kibibyte instead.
Declaration
public double Kilobyte { get; set; }
Property Value
| Type | Description |
|---|---|
| double |
Exceptions
| Type | Condition |
|---|---|
| ArgumentOutOfRangeException | Thrown by the setter if the assigned value is negative, NaN, or infinite. |
Mebibyte
Gets or sets the data size expressed in mebibytes (MiB) using the IEC binary convention, where 1 MiB = 1024^2 bytes (1,048,576 bytes). For the SI decimal equivalent, use Megabyte instead.
Declaration
public double Mebibyte { get; set; }
Property Value
| Type | Description |
|---|---|
| double |
Exceptions
| Type | Condition |
|---|---|
| ArgumentOutOfRangeException | Thrown by the setter if the assigned value is negative, NaN, or infinite. |
Megabit
Gets or sets the data size expressed in megabits (Mb) using the SI decimal convention, where 1 Mb = 1,000,000 bits (1000^2). Megabits are widely used for internet connection speeds (e.g., 100 Mb/s broadband).
Declaration
public double Megabit { get; set; }
Property Value
| Type | Description |
|---|---|
| double |
Exceptions
| Type | Condition |
|---|---|
| ArgumentOutOfRangeException | Thrown by the setter if the assigned value is negative, NaN, or infinite. |
Megabyte
Gets or sets the data size expressed in megabytes (MB) using the SI decimal convention, where 1 MB = 1,000,000 bytes (1000^2). For the binary equivalent, use Mebibyte instead.
Declaration
public double Megabyte { get; set; }
Property Value
| Type | Description |
|---|---|
| double |
Exceptions
| Type | Condition |
|---|---|
| ArgumentOutOfRangeException | Thrown by the setter if the assigned value is negative, NaN, or infinite. |
Nibble
Gets or sets the data size expressed in nibbles, where one nibble equals 4 bits (half a byte). Two nibbles make up one byte. Setting this property converts the nibble count to bytes for internal storage. The value must be finite and non-negative.
Declaration
public double Nibble { get; set; }
Property Value
| Type | Description |
|---|---|
| double |
Exceptions
| Type | Condition |
|---|---|
| ArgumentOutOfRangeException | Thrown by the setter if the assigned value is negative, NaN, or infinite. |
Pebibyte
Gets or sets the data size expressed in pebibytes (PiB) using the IEC binary convention, where 1 PiB = 1024^5 bytes. For the SI decimal equivalent, use Petabyte instead.
Declaration
public double Pebibyte { get; set; }
Property Value
| Type | Description |
|---|---|
| double |
Exceptions
| Type | Condition |
|---|---|
| ArgumentOutOfRangeException | Thrown by the setter if the assigned value is negative, NaN, or infinite. |
Petabit
Gets or sets the data size expressed in petabits (Pb) using the SI decimal convention, where 1 Pb = 1000^5 bits.
Declaration
public double Petabit { get; set; }
Property Value
| Type | Description |
|---|---|
| double |
Exceptions
| Type | Condition |
|---|---|
| ArgumentOutOfRangeException | Thrown by the setter if the assigned value is negative, NaN, or infinite. |
Petabyte
Gets or sets the data size expressed in petabytes (PB) using the SI decimal convention, where 1 PB = 1000^5 bytes. For the binary equivalent, use Pebibyte instead.
Declaration
public double Petabyte { get; set; }
Property Value
| Type | Description |
|---|---|
| double |
Exceptions
| Type | Condition |
|---|---|
| ArgumentOutOfRangeException | Thrown by the setter if the assigned value is negative, NaN, or infinite. |
Quettabit
Gets or sets the data size expressed in quettabits (Qb) using the SI decimal convention, where 1 Qb = 1000^10 bits. This is the largest named SI bit-scale prefix.
Declaration
public double Quettabit { get; set; }
Property Value
| Type | Description |
|---|---|
| double |
Exceptions
| Type | Condition |
|---|---|
| ArgumentOutOfRangeException | Thrown by the setter if the assigned value is negative, NaN, or infinite. |
Quettabyte
Gets or sets the data size expressed in quettabytes (QB) using the SI decimal convention, where 1 QB = 1000^10 bytes. Quettabyte is the largest named SI prefix for data (introduced in 2022), representing 10^30 bytes.
Declaration
public double Quettabyte { get; set; }
Property Value
| Type | Description |
|---|---|
| double |
Exceptions
| Type | Condition |
|---|---|
| ArgumentOutOfRangeException | Thrown by the setter if the assigned value is negative, NaN, or infinite. |
Ronnabit
Gets or sets the data size expressed in ronnabits (Rb) using the SI decimal convention, where 1 Rb = 1000^9 bits.
Declaration
public double Ronnabit { get; set; }
Property Value
| Type | Description |
|---|---|
| double |
Exceptions
| Type | Condition |
|---|---|
| ArgumentOutOfRangeException | Thrown by the setter if the assigned value is negative, NaN, or infinite. |
Ronnabyte
Gets or sets the data size expressed in ronnabytes (RB) using the SI decimal convention, where 1 RB = 1000^9 bytes. Ronnabyte is an SI prefix introduced in 2022 for use at planetary-scale data magnitudes.
Declaration
public double Ronnabyte { get; set; }
Property Value
| Type | Description |
|---|---|
| double |
Exceptions
| Type | Condition |
|---|---|
| ArgumentOutOfRangeException | Thrown by the setter if the assigned value is negative, NaN, or infinite. |
Tebibyte
Gets or sets the data size expressed in tebibytes (TiB) using the IEC binary convention, where 1 TiB = 1024^4 bytes. For the SI decimal equivalent, use Terabyte instead.
Declaration
public double Tebibyte { get; set; }
Property Value
| Type | Description |
|---|---|
| double |
Exceptions
| Type | Condition |
|---|---|
| ArgumentOutOfRangeException | Thrown by the setter if the assigned value is negative, NaN, or infinite. |
Terabit
Gets or sets the data size expressed in terabits (Tb) using the SI decimal convention, where 1 Tb = 1000^4 bits.
Declaration
public double Terabit { get; set; }
Property Value
| Type | Description |
|---|---|
| double |
Exceptions
| Type | Condition |
|---|---|
| ArgumentOutOfRangeException | Thrown by the setter if the assigned value is negative, NaN, or infinite. |
Terabyte
Gets or sets the data size expressed in terabytes (TB) using the SI decimal convention, where 1 TB = 1000^4 bytes. For the binary equivalent, use Tebibyte instead.
Declaration
public double Terabyte { get; set; }
Property Value
| Type | Description |
|---|---|
| double |
Exceptions
| Type | Condition |
|---|---|
| ArgumentOutOfRangeException | Thrown by the setter if the assigned value is negative, NaN, or infinite. |
Yobibyte
Gets or sets the data size expressed in yobibytes (YiB) using the IEC binary convention, where 1 YiB = 1024^8 bytes. This is the largest standardized IEC binary prefix. For the SI decimal equivalent, use Yottabyte instead.
Declaration
public double Yobibyte { get; set; }
Property Value
| Type | Description |
|---|---|
| double |
Exceptions
| Type | Condition |
|---|---|
| ArgumentOutOfRangeException | Thrown by the setter if the assigned value is negative, NaN, or infinite. |
Yottabit
Gets or sets the data size expressed in yottabits (Yb) using the SI decimal convention, where 1 Yb = 1000^8 bits.
Declaration
public double Yottabit { get; set; }
Property Value
| Type | Description |
|---|---|
| double |
Exceptions
| Type | Condition |
|---|---|
| ArgumentOutOfRangeException | Thrown by the setter if the assigned value is negative, NaN, or infinite. |
Yottabyte
Gets or sets the data size expressed in yottabytes (YB) using the SI decimal convention, where 1 YB = 1000^8 bytes. For the binary equivalent, use Yobibyte instead.
Declaration
public double Yottabyte { get; set; }
Property Value
| Type | Description |
|---|---|
| double |
Exceptions
| Type | Condition |
|---|---|
| ArgumentOutOfRangeException | Thrown by the setter if the assigned value is negative, NaN, or infinite. |
Zebibyte
Gets or sets the data size expressed in zebibytes (ZiB) using the IEC binary convention, where 1 ZiB = 1024^7 bytes. For the SI decimal equivalent, use Zettabyte instead.
Declaration
public double Zebibyte { get; set; }
Property Value
| Type | Description |
|---|---|
| double |
Exceptions
| Type | Condition |
|---|---|
| ArgumentOutOfRangeException | Thrown by the setter if the assigned value is negative, NaN, or infinite. |
Zettabit
Gets or sets the data size expressed in zettabits (Zb) using the SI decimal convention, where 1 Zb = 1000^7 bits.
Declaration
public double Zettabit { get; set; }
Property Value
| Type | Description |
|---|---|
| double |
Exceptions
| Type | Condition |
|---|---|
| ArgumentOutOfRangeException | Thrown by the setter if the assigned value is negative, NaN, or infinite. |
Zettabyte
Gets or sets the data size expressed in zettabytes (ZB) using the SI decimal convention, where 1 ZB = 1000^7 bytes. For the binary equivalent, use Zebibyte instead.
Declaration
public double Zettabyte { get; set; }
Property Value
| Type | Description |
|---|---|
| double |
Exceptions
| Type | Condition |
|---|---|
| ArgumentOutOfRangeException | Thrown by the setter if the assigned value is negative, NaN, or infinite. |
Methods
Equals(DataUnit)
Determines whether the specified DataUnit is equal to this instance.
Comparison is performed using NumberUtil.Approximately on the raw byte
counts to tolerate floating-point rounding from repeated unit conversions.
Declaration
public bool Equals(DataUnit other)
Parameters
| Type | Name | Description |
|---|---|---|
| DataUnit | other | The DataUnit to compare with this instance. |
Returns
| Type | Description |
|---|---|
| bool | true if |
Equals(object)
Determines whether the specified object is equal to this DataUnit
instance. Only returns true when obj is
itself a DataUnit with an approximately equal byte count.
Declaration
public override bool Equals(object obj)
Parameters
| Type | Name | Description |
|---|---|---|
| object | obj | The object to compare with this instance. May be null. |
Returns
| Type | Description |
|---|---|
| bool | true if |
Overrides
GetHashCode()
Returns a hash code derived from the raw byte count of this instance, suitable for use in hash tables and dictionaries.
Declaration
public override int GetHashCode()
Returns
| Type | Description |
|---|---|
| int | A 32-bit integer hash code based on the internal |
Overrides
ToString()
Returns a human-readable string that expresses the stored size in the most appropriate SI byte unit for the current magnitude.
Declaration
public override string ToString()
Returns
| Type | Description |
|---|---|
| string | A formatted string such as Selection logic from smallest to largest:
Numeric formatting uses two decimal places for values below 10, one decimal place for values below 100, and zero decimal places otherwise. Trailing zeros and redundant decimal points are trimmed. |
Overrides
Operators
operator +(DataUnit, DataUnit)
Adds two DataUnit instances together, combining their byte values.
Declaration
public static DataUnit operator +(DataUnit left, DataUnit right)
Parameters
| Type | Name | Description |
|---|---|---|
| DataUnit | left | The first operand. |
| DataUnit | right | The second operand. |
Returns
| Type | Description |
|---|---|
| DataUnit | A new DataUnit whose internal byte count equals the sum of
|
operator /(DataUnit, DataUnit)
Divides one DataUnit by another, returning the dimensionless ratio
of their byte counts as a double. Useful for computing what fraction one
size is of another (e.g., how full a buffer is).
Declaration
public static double operator /(DataUnit left, DataUnit right)
Parameters
| Type | Name | Description |
|---|---|---|
| DataUnit | left | The dividend. |
| DataUnit | right | The divisor. Must represent a non-zero byte count. |
Returns
| Type | Description |
|---|---|
| double | The ratio |
Exceptions
| Type | Condition |
|---|---|
| DivideByZeroException | Thrown if |
operator /(DataUnit, double)
Divides a DataUnit by a double-precision floating-point scalar, producing a proportionally smaller data size.
Declaration
public static DataUnit operator /(DataUnit left, double right)
Parameters
| Type | Name | Description |
|---|---|---|
| DataUnit | left | The DataUnit dividend. |
| double | right | The scalar divisor. Must be a finite, non-zero value greater than zero to keep the result non-negative. |
Returns
| Type | Description |
|---|---|
| DataUnit | A new DataUnit whose byte count equals
|
Exceptions
| Type | Condition |
|---|---|
| DivideByZeroException | Thrown if |
operator /(DataUnit, int)
Divides a DataUnit by an integer scalar, producing a proportionally smaller data size.
Declaration
public static DataUnit operator /(DataUnit left, int right)
Parameters
| Type | Name | Description |
|---|---|---|
| DataUnit | left | The DataUnit dividend. |
| int | right | The integer scalar divisor. Must not be zero. |
Returns
| Type | Description |
|---|---|
| DataUnit | A new DataUnit whose byte count equals
|
Exceptions
| Type | Condition |
|---|---|
| DivideByZeroException | Thrown if |
operator ==(DataUnit, DataUnit)
Determines whether two DataUnit instances represent the same data
size. Uses NumberUtil.Approximately to guard against floating-point rounding
artifacts that may arise from unit conversions.
Declaration
public static bool operator ==(DataUnit left, DataUnit right)
Parameters
| Type | Name | Description |
|---|---|---|
| DataUnit | left | The left operand. |
| DataUnit | right | The right operand. |
Returns
| Type | Description |
|---|---|
| bool | true if the byte counts of |
operator >(DataUnit, DataUnit)
Determines whether one DataUnit represents a strictly larger data size than another. Uses exact byte-level comparison (not approximate equality).
Declaration
public static bool operator >(DataUnit left, DataUnit right)
Parameters
| Type | Name | Description |
|---|---|---|
| DataUnit | left | The left operand. |
| DataUnit | right | The right operand. |
Returns
| Type | Description |
|---|---|
| bool |
operator >=(DataUnit, DataUnit)
Determines whether one DataUnit represents a data size that is greater than or equal to another. Uses exact byte-level comparison (not approximate equality).
Declaration
public static bool operator >=(DataUnit left, DataUnit right)
Parameters
| Type | Name | Description |
|---|---|---|
| DataUnit | left | The left operand. |
| DataUnit | right | The right operand. |
Returns
| Type | Description |
|---|---|
| bool | true if |
operator !=(DataUnit, DataUnit)
Determines whether two DataUnit instances represent different data
sizes. Uses NumberUtil.Approximately for comparison, mirroring the behaviour
of the == operator.
Declaration
public static bool operator !=(DataUnit left, DataUnit right)
Parameters
| Type | Name | Description |
|---|---|---|
| DataUnit | left | The left operand. |
| DataUnit | right | The right operand. |
Returns
| Type | Description |
|---|---|
| bool | true if the byte counts of |
operator <(DataUnit, DataUnit)
Determines whether one DataUnit represents a strictly smaller data size than another. Uses exact byte-level comparison (not approximate equality).
Declaration
public static bool operator <(DataUnit left, DataUnit right)
Parameters
| Type | Name | Description |
|---|---|---|
| DataUnit | left | The left operand. |
| DataUnit | right | The right operand. |
Returns
| Type | Description |
|---|---|
| bool |
operator <=(DataUnit, DataUnit)
Determines whether one DataUnit represents a data size that is less than or equal to another. Uses exact byte-level comparison (not approximate equality).
Declaration
public static bool operator <=(DataUnit left, DataUnit right)
Parameters
| Type | Name | Description |
|---|---|---|
| DataUnit | left | The left operand. |
| DataUnit | right | The right operand. |
Returns
| Type | Description |
|---|---|
| bool | true if |
operator *(DataUnit, double)
Multiplies a DataUnit by a double-precision floating-point scalar, scaling the stored byte count proportionally.
Declaration
public static DataUnit operator *(DataUnit left, double right)
Parameters
| Type | Name | Description |
|---|---|---|
| DataUnit | left | The DataUnit operand. |
| double | right | The scalar multiplier. |
Returns
| Type | Description |
|---|---|
| DataUnit | A new DataUnit whose byte count equals
|
operator *(DataUnit, int)
Multiplies a DataUnit by an integer scalar, scaling the stored byte count by an exact whole-number factor.
Declaration
public static DataUnit operator *(DataUnit left, int right)
Parameters
| Type | Name | Description |
|---|---|---|
| DataUnit | left | The DataUnit operand. |
| int | right | The integer scalar multiplier. |
Returns
| Type | Description |
|---|---|
| DataUnit | A new DataUnit whose byte count equals
|
operator *(double, DataUnit)
Multiplies a double-precision floating-point scalar by a DataUnit,
scaling the stored byte count proportionally. This overload allows scalar-first syntax
such as 2.5 * someDataUnit.
Declaration
public static DataUnit operator *(double left, DataUnit right)
Parameters
| Type | Name | Description |
|---|---|---|
| double | left | The scalar multiplier. |
| DataUnit | right | The DataUnit operand. |
Returns
| Type | Description |
|---|---|
| DataUnit | A new DataUnit whose byte count equals
|
operator *(int, DataUnit)
Multiplies an integer scalar by a DataUnit, scaling the stored
byte count by an exact whole-number factor. This overload allows integer-first
syntax such as 4 * someDataUnit.
Declaration
public static DataUnit operator *(int left, DataUnit right)
Parameters
| Type | Name | Description |
|---|---|---|
| int | left | The integer scalar multiplier. |
| DataUnit | right | The DataUnit operand. |
Returns
| Type | Description |
|---|---|
| DataUnit | A new DataUnit whose byte count equals
|
operator -(DataUnit, DataUnit)
Subtracts one DataUnit instance from another. Because DataUnit values are always non-negative, the result is validated and an exception is thrown if the subtraction would produce a negative size.
Declaration
public static DataUnit operator -(DataUnit left, DataUnit right)
Parameters
| Type | Name | Description |
|---|---|---|
| DataUnit | left | The minuend (the value to subtract from). |
| DataUnit | right | The subtrahend (the value to subtract). |
Returns
| Type | Description |
|---|---|
| DataUnit | A new DataUnit whose byte count equals
|
Exceptions
| Type | Condition |
|---|---|
| ArgumentOutOfRangeException | Thrown if the result would be negative (i.e., |