> ## Documentation Index
> Fetch the complete documentation index at: https://voltaire.tevm.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# SDIV (0x05)

> Signed integer division using two's complement representation

<Warning>
  **This page is a placeholder.** All examples on this page are currently AI-generated and are not correct. This documentation will be completed in the future with accurate, tested examples.
</Warning>

## Overview

**Opcode:** `0x05`
**Introduced:** Frontier (EVM genesis)

SDIV performs signed integer division on two 256-bit values interpreted as two's complement signed integers. The result is truncated toward zero (not toward negative infinity like some languages).

Like DIV, division by zero returns 0. Additionally, SDIV has special handling for the edge case of dividing the minimum signed integer by -1.

## Specification

**Stack Input:**

```
a (top - signed dividend)
b (signed divisor)
```

**Stack Output:**

```
a / b  (if b ≠ 0 and not MIN_INT/-1)
MIN_INT (if a = MIN_INT and b = -1)
0      (if b = 0)
```

**Gas Cost:** 5 (GasFastStep)

**Operation:**

```
Two's complement interpretation:
- Range: -2^255 to 2^255 - 1
- MIN_INT: -2^255 = 0x8000...0000
- -1: 2^256 - 1 = 0xFFFF...FFFF
```

## Behavior

SDIV interprets 256-bit values as signed integers using two's complement:

* Bit 255 (MSB) determines sign: 0 = positive, 1 = negative
* If `b = 0`: Returns 0 (no exception)
* If `a = MIN_INT` and `b = -1`: Returns MIN\_INT (overflow case)
* Otherwise: Returns `a / b` truncated toward zero

**Truncation toward zero:**

* Positive quotient: rounds down (e.g., 7/2 = 3)
* Negative quotient: rounds up (e.g., -7/2 = -3, not -4)

## Examples

### Basic Signed Division

```typescript theme={null}
import { sdiv } from '@tevm/voltaire/evm/arithmetic';
import { createFrame } from '@tevm/voltaire/evm/Frame';

// 10 / 2 = 5
const frame = createFrame({ stack: [10n, 2n] });
const err = sdiv(frame);

console.log(frame.stack); // [5n]
```

### Negative Dividend

```typescript theme={null}
// -10 / 2 = -5
// -10 in two's complement: 2^256 - 10
const neg10 = (1n << 256n) - 10n;
const frame = createFrame({ stack: [neg10, 2n] });
sdiv(frame);

// Result: -5 in two's complement
const neg5 = (1n << 256n) - 5n;
console.log(frame.stack); // [neg5]
```

### Negative Divisor

```typescript theme={null}
// 10 / -2 = -5
const neg2 = (1n << 256n) - 2n;
const frame = createFrame({ stack: [10n, neg2] });
sdiv(frame);

const neg5 = (1n << 256n) - 5n;
console.log(frame.stack); // [neg5]
```

### Both Negative

```typescript theme={null}
// -10 / -2 = 5 (negative / negative = positive)
const neg10 = (1n << 256n) - 10n;
const neg2 = (1n << 256n) - 2n;
const frame = createFrame({ stack: [neg10, neg2] });
sdiv(frame);

console.log(frame.stack); // [5n]
```

### Truncation Toward Zero

```typescript theme={null}
// 7 / 2 = 3 (not 4)
const frame1 = createFrame({ stack: [7n, 2n] });
sdiv(frame1);
console.log(frame1.stack); // [3n]

// -7 / 2 = -3 (not -4)
// Rounds toward zero, not negative infinity
const neg7 = (1n << 256n) - 7n;
const frame2 = createFrame({ stack: [neg7, 2n] });
sdiv(frame2);

const neg3 = (1n << 256n) - 3n;
console.log(frame2.stack); // [neg3]
```

### MIN\_INT / -1 Edge Case

```typescript theme={null}
// MIN_INT / -1 would overflow to 2^255 (not representable)
// SDIV returns MIN_INT instead
const MIN_INT = 1n << 255n;
const negOne = (1n << 256n) - 1n;
const frame = createFrame({ stack: [MIN_INT, negOne] });
sdiv(frame);

console.log(frame.stack); // [MIN_INT]
```

## Gas Cost

**Cost:** 5 gas (GasFastStep)

SDIV has the same gas cost as DIV despite additional sign handling:

**Comparison:**

* ADD/SUB: 3 gas
* **MUL/DIV/MOD/SDIV/SMOD/SIGNEXTEND:** 5 gas
* ADDMOD/MULMOD: 8 gas

The sign interpretation adds no gas overhead.

## Edge Cases

### Division by Zero

```typescript theme={null}
// Signed division by zero returns 0
const neg10 = (1n << 256n) - 10n;
const frame = createFrame({ stack: [neg10, 0n] });
sdiv(frame);

console.log(frame.stack); // [0n]
```

### MIN\_INT Special Cases

```typescript theme={null}
// MIN_INT / -1 = MIN_INT (overflow case)
const MIN_INT = 1n << 255n;
const negOne = (1n << 256n) - 1n;
const frame1 = createFrame({ stack: [MIN_INT, negOne] });
sdiv(frame1);
console.log(frame1.stack); // [MIN_INT]

// MIN_INT / 1 = MIN_INT (no overflow)
const frame2 = createFrame({ stack: [MIN_INT, 1n] });
sdiv(frame2);
console.log(frame2.stack); // [MIN_INT]

// MIN_INT / MIN_INT = 1
const frame3 = createFrame({ stack: [MIN_INT, MIN_INT] });
sdiv(frame3);
console.log(frame3.stack); // [1n]
```

### Zero Division Results

```typescript theme={null}
// 0 / -5 = 0
const neg5 = (1n << 256n) - 5n;
const frame = createFrame({ stack: [0n, neg5] });
sdiv(frame);

console.log(frame.stack); // [0n]
```

## Common Usage

### Signed Arithmetic

```solidity theme={null}
// Calculate price change (can be negative)
function priceChange(int256 oldPrice, int256 newPrice)
    pure returns (int256) {
    return newPrice - oldPrice;  // Can be negative
}

// Average of signed values
function signedAverage(int256 a, int256 b)
    pure returns (int256) {
    // Must handle negative results correctly
    assembly {
        let sum := add(a, b)
        let result := sdiv(sum, 2)
        mstore(0, result)
        return(0, 32)
    }
}
```

### Directional Calculations

```solidity theme={null}
// Calculate slope (can be negative)
function slope(int256 y2, int256 y1, int256 x2, int256 x1)
    pure returns (int256) {
    require(x2 != x1, "vertical line");
    int256 dy = y2 - y1;
    int256 dx = x2 - x1;

    assembly {
        let result := sdiv(dy, dx)
        mstore(0, result)
        return(0, 32)
    }
}
```

### Fixed-Point Signed Math

```solidity theme={null}
// Signed fixed-point division
int256 constant FIXED_POINT = 1e18;

function signedWdiv(int256 x, int256 y) pure returns (int256) {
    require(y != 0, "division by zero");

    assembly {
        let result := sdiv(mul(x, FIXED_POINT), y)
        mstore(0, result)
        return(0, 32)
    }
}
```

## Implementation

<Tabs>
  <Tab title="TypeScript">
    ```typescript theme={null}
    /**
     * SDIV opcode (0x05) - Signed integer division
     */
    export function sdiv(frame: FrameType): EvmError | null {
      // Consume gas (GasFastStep = 5)
      frame.gasRemaining -= 5n;
      if (frame.gasRemaining < 0n) {
        frame.gasRemaining = 0n;
        return { type: "OutOfGas" };
      }

      // Pop operands
      if (frame.stack.length < 2) return { type: "StackUnderflow" };
      const a = frame.stack.pop();
      const b = frame.stack.pop();

      let result: bigint;

      if (b === 0n) {
        result = 0n;
      } else {
        const MIN_INT = 1n << 255n;
        const MAX_UINT = (1n << 256n) - 1n;

        // Special case: MIN_INT / -1 would overflow
        if (a === MIN_INT && b === MAX_UINT) {
          result = MIN_INT;
        } else {
          // Convert to signed, divide, convert back
          const aSigned = a < MIN_INT ? a : a - (1n << 256n);
          const bSigned = b < MIN_INT ? b : b - (1n << 256n);
          const quotient = aSigned / bSigned;  // BigInt division truncates toward zero
          result = quotient < 0n ? (1n << 256n) + quotient : quotient;
        }
      }

      // Push result
      if (frame.stack.length >= 1024) return { type: "StackOverflow" };
      frame.stack.push(result);

      // Increment PC
      frame.pc += 1;

      return null;
    }
    ```
  </Tab>
</Tabs>

## Testing

### Test Coverage

```typescript theme={null}
import { describe, it, expect } from 'vitest';
import { sdiv } from './0x05_SDIV.js';

describe('SDIV (0x05)', () => {
  const MIN_INT = 1n << 255n;
  const MAX_UINT = (1n << 256n) - 1n;
  const toSigned = (n: bigint) => n < 0n ? (1n << 256n) + n : n;

  it('divides positive numbers', () => {
    const frame = createFrame([10n, 2n]);
    expect(sdiv(frame)).toBeNull();
    expect(frame.stack).toEqual([5n]);
  });

  it('handles negative dividend', () => {
    const frame = createFrame([toSigned(-10n), 2n]);
    expect(sdiv(frame)).toBeNull();
    expect(frame.stack).toEqual([toSigned(-5n)]);
  });

  it('handles negative divisor', () => {
    const frame = createFrame([10n, toSigned(-2n)]);
    expect(sdiv(frame)).toBeNull();
    expect(frame.stack).toEqual([toSigned(-5n)]);
  });

  it('handles both negative', () => {
    const frame = createFrame([toSigned(-10n), toSigned(-2n)]);
    expect(sdiv(frame)).toBeNull();
    expect(frame.stack).toEqual([5n]);
  });

  it('truncates toward zero (positive)', () => {
    const frame = createFrame([7n, 2n]);
    expect(sdiv(frame)).toBeNull();
    expect(frame.stack).toEqual([3n]);
  });

  it('truncates toward zero (negative)', () => {
    const frame = createFrame([toSigned(-7n), 2n]);
    expect(sdiv(frame)).toBeNull();
    expect(frame.stack).toEqual([toSigned(-3n)]);
  });

  it('handles MIN_INT / -1 overflow case', () => {
    const frame = createFrame([MIN_INT, MAX_UINT]);
    expect(sdiv(frame)).toBeNull();
    expect(frame.stack).toEqual([MIN_INT]);
  });

  it('handles division by zero', () => {
    const frame = createFrame([toSigned(-10n), 0n]);
    expect(sdiv(frame)).toBeNull();
    expect(frame.stack).toEqual([0n]);
  });
});
```

## Security

### Sign Interpretation

```solidity theme={null}
// Unsigned vs signed division give different results
uint256 a = type(uint256).max;  // Max uint = -1 signed
uint256 b = 2;

// Unsigned: MAX / 2 = 2^255 - 1
uint256 unsignedResult;
assembly { unsignedResult := div(a, b) }

// Signed: -1 / 2 = 0 (truncate toward zero)
uint256 signedResult;
assembly { signedResult := sdiv(a, b) }

// Results are different!
```

### MIN\_INT Overflow

```solidity theme={null}
// MIN_INT / -1 special case
int256 MIN = type(int256).min;  // -2^255
int256 result = MIN / -1;  // In Solidity, this reverts!

// But in assembly (raw SDIV):
assembly {
    // Returns MIN_INT, does not revert
    result := sdiv(MIN, sub(0, 1))
}
```

### Truncation Behavior

```solidity theme={null}
// Different languages handle negative division differently

// EVM SDIV: Truncates toward zero
// -7 / 2 = -3

// Python, Ruby: Floor division (toward negative infinity)
// -7 // 2 = -4

// Always verify truncation direction matches expectations
```

### Safe Signed Division

```solidity theme={null}
// Solidity 0.8.0+ automatically checks
function safeSdiv(int256 a, int256 b) pure returns (int256) {
    return a / b;  // Reverts on MIN_INT / -1 or b = 0
}

// Explicit checks for assembly usage
function assemblySdiv(int256 a, int256 b) pure returns (int256) {
    require(b != 0, "division by zero");
    require(!(a == type(int256).min && b == -1), "overflow");

    int256 result;
    assembly {
        result := sdiv(a, b)
    }
    return result;
}
```

## Benchmarks

SDIV performance identical to DIV:

**Execution time:**

* ADD: 1.0x
* MUL: 1.2x
* **SDIV: 2.5x** (same as DIV)

**Gas cost:**

* 5 gas per signed division
* No overhead for sign handling
* \~200,000 signed divisions per million gas

## References

* [Yellow Paper](https://ethereum.github.io/yellowpaper/paper.pdf) - Section 9.1 (Arithmetic Operations)
* [EVM Codes - SDIV](https://www.evm.codes/#05)
* [Two's Complement](https://en.wikipedia.org/wiki/Two%27s_complement)
* [Solidity Docs - Signed Integers](https://docs.soliditylang.org/en/latest/types.html#integers)
