# 분리된 구간 집합 위에서 계산하는 계산기

> Clean Markdown view of GeekNews topic #28675. Use the original source for factual precision when an external source URL is present.

## Metadata

- GeekNews HTML: [https://news.hada.io/topic?id=28675](https://news.hada.io/topic?id=28675)
- GeekNews Markdown: [https://news.hada.io/topic/28675.md](https://news.hada.io/topic/28675.md)
- Type: GN+
- Author: [neo](https://news.hada.io/@neo)
- Published: 2026-04-19T10:01:14+09:00
- Updated: 2026-04-19T10:01:14+09:00
- Original source: [victorpoughon.github.io](https://victorpoughon.github.io/interval-calculator/)
- Points: 1
- Comments: 1

## Topic Body

- **분리된 구간들의 합집합**을 입력으로 받아 사칙연산, 함수 호출, 거듭제곱까지 수행하며, **interval union arithmetic**를 브라우저에서 직접 계산 가능
- 결과 구간은 입력 합집합에서 고른 값들로 같은 식을 실수 위에서 계산했을 때의 값을 **반드시 포함**하며, **0을 포함하는 구간으로의 나눗셈**도 분리된 합집합 형태로 처리 가능
- `1 / [-2, 1]`에서 `[-∞, -0.5] U [1, +∞]`가 나오고 `tan([pi/3, 2*pi/3])`에서 `[-∞, -1.732] U [1.732, +∞]`가 나오는 식으로, **불연속 구간 결과**와 **무한대 경계** 표현 지원
- `[a, b]`, `[a, b] U [c, d]`, 중첩 구간 문법, `lo`, `hi`, `hull`, `log10`, `cos`, `min`, `max` 같은 **다양한 표기와 함수** 지원
- **전체 정밀도 모드**에서는 IEEE 754 배정밀도 기반 바깥쪽 반올림으로 실제 값을 감싸는 구간을 반환하며, `0.1 + 0.2`를 `[0.29999999999999993, 0.3000000000000001]`로 보여주는 점이 특징

---

### 개요
- **분리된 구간들의 합집합**을 대상으로 계산하는 계산기이며, 일반 실수뿐 아니라 **interval union arithmetic** 구현 지원
  - 구간 `[a, b]`는 a부터 b까지의 수 전체를 뜻하고, `[a, b] U [c, d]`는 서로 떨어진 구간들의 합집합 의미
  - 일반 구간 산술의 확장 형태이며, **0을 포함하는 구간으로의 나눗셈**도 닫힘 성질을 유지한 채 계산 가능
- 포함 성질 보장
  - 입력 합집합들에서 각각 임의의 실수를 하나씩 선택해 같은 식을 실수 위에서 계산하면, 그 결과가 출력 합집합 안에 반드시 포함되는 구조
- 불확실성 표현 가능
  - `50 * (10 + [-1, 1])` 계산 결과 `[450, 550]` 예시 제공
- 복잡한 구간 식 계산 지원
  - `U` 연산자를 사용해 `( [5, 10] U [15, 16] ) / [10, 100]` 같은 식 입력 가능
  - 결과 `[0.05, 1.6]` 예시 제공
- 연산 결과가 분리된 합집합이 될 수 있음
  - `1 / [-2, 1]` 결과 `[-∞, -0.5] U [1, +∞]`
  - `tan([pi/3, 2*pi/3])` 결과 `[-∞, -1.732] U [1.732, +∞]`
- 전체 정밀도 모드에서는 일반 계산기처럼 사용할 수 있으면서도 **부동소수점 정밀도 문제**를 포함한 실제 값을 감싸는 구간 결과 제공
  - `0.1 + 0.2` 결과 `[0.29999999999999993, 0.3000000000000001]` 예시 제시

### 문법
- 기본 표기 지원
  - 구간 표기 `[a, b]` 지원
  - 예시 `[0.5, 0.6]`
- 합집합 표기 지원
  - `[a, b] U [c, d]` 형태 지원
  - 예시 `[0, 1] U [5, 6]`
- 사칙연산 및 거듭제곱 지원
  - 덧셈 `A + B` 예시 `➤ [90, 100] + [-2, 2]` 결과 `[88, 102]`
  - 뺄셈 `A - B` 예시 `➤ [14, 16] - [8, 12]` 결과 `[2, 8]`
  - 곱셈 `A * B` 예시 `➤ [-5, 10] * [2, 4]` 결과 `[-20, 40]`
  - 나눗셈 `A / B` 예시 `➤ [2, 4] / [-1, 2]` 결과 `[-∞, -2] U [1, +∞]`
  - 거듭제곱 `A ^ B` 예시 `➤ [2, 3] ^ [-2, 3]` 결과 `[0.1111, 27]`
- 함수와 상수 지원
  - 함수 호출 `function(...)` 형태 지원
  - `log10([1, 10000])` 결과 `[0, 4]`
  - 상수 이름 입력 지원
  - `pi` 결과 `[3.1415926535897927, 3.1415926535897936]`
- 숫자와 구간 혼합 입력 가능
  - `[1, 2]`처럼 대괄호 구문으로 구간 입력 가능
  - `3.14` 같은 숫자는 폭이 0인 좁은 구간 `[3.14, 3.14]`로 해석됨
  - 전체 정밀도 모드에서는 이에 관련된 세부 차이 존재
  - `1.55 + [-0.002, 0.002]` 결과 `[1.548, 1.552]`
- 중첩 구간 문법 지원
  - `[0, [0, 100]]` 입력 가능하며 결과 `[0, 100]`
  - 구간 경계를 정의하는 내부 숫자들까지 모두 구간으로 해석되는 구조
  - 중첩된 구간에서 경계 자리에 들어간 구간은 그 구간의 상한을 취하는 방식
  - 이 설계로 경계 자체에 산술 적용 가능
  - `[0, cos(2*pi)]` 결과 `[0, 1]`

### 지원 함수
- 상수 지원
  - `inf`, `∞`, `pi`, `e` 지원
  - `[-inf, 0] * [-inf, 0]` 결과 `[0, +∞]`
- 경계 추출 함수 지원
  - `lo(A)`는 하한 반환
    - `lo([1, 2])` 결과 `[1, 1]`
  - `hi(A)`는 상한 반환
    - `hi([1, 2])` 결과 `[2, 2]`
- 구간 외피 계산 지원
  - `hull(A)`는 합집합을 하나의 구간으로 감싸는 형태
  - `hull([1, 2] U [99, 100])` 결과 `[1, 100]`
- 기본 수학 함수 지원
  - `abs(A)` 예시 `abs([-10, 5])` 결과 `[0, 10]`
  - `sqrt(A)` 예시 `sqrt([9, 49])` 결과 `[3, 7]`
  - `sqinv(A)` 예시 `sqinv([4, 64])` 결과 `[-8, -2] U [2, 8]`
- 로그 및 지수 함수 지원
  - `log(A)` 예시 `log([0, 1])` 결과 `[-∞, 0]`
  - `log2(A)` 예시 `log2([64, 1024])` 결과 `[6, 10]`
  - `log10(A)` 예시 `log10([0.0001, 1])` 결과 `[-4, 0]`
  - `exp(A)` 예시 `exp([-∞, 0] U [1, 2])` 결과 `[0, 1] U [2.718, 7.389]`
- 삼각함수 및 역삼각함수 지원
  - `cos(A)` 예시 `cos([pi/3, pi])` 결과 `[-1, 0.5]`
  - `sin(A)` 예시 `sin([pi/6, 5*pi/6])` 결과 `[0.5, 1]`
  - `tan(A)` 예시 `tan([pi/3, 2*pi/3])` 결과 `[-∞, -1.732] U [1.732, +∞]`
  - `acos(A)` 예시 `acos([-1/2, 1/2])` 결과 `[1.047, 2.094]`
  - `asin(A)` 예시 `asin([0, 1])` 결과 `[0, 1.571]`
  - `atan(A)` 예시 `atan([-10, 2])` 결과 `[-1.471, 1.107]`
- 최소값·최대값 함수 지원
  - `min(A, B)` 예시 `min([1, 2], [0, 6])` 결과 `[0, 2]`
  - `max(A, B)` 예시 `max([0, 10], [5, 6])` 결과 `[5, 10]`

### 전체 정밀도 모드
- IEEE 754 배정밀도 부동소수점 위에서 **바깥쪽 반올림** 구현
  - JavaScript의 number 타입 사용
  - 같은 식을 실수와 무한 정밀도로 계산했을 때의 실제 값을 결과 구간이 반드시 포함하는 보장
- `0.1 + 0.2` 사례 포함
  - `0.3`은 배정밀도 부동소수점으로 정확히 표현되지 않음
  - interval arithmetic는 `0.3`을 포함하는 구간 계산 수행
- 전체 정밀도 모드 활성화 시 동작
  - 사용자가 입력한 숫자는 입력한 10진 표현에 가장 가까운 IEEE 754 값을 포함하되, 양쪽 경계가 그 값과 같지 않은 **가장 작은 구간**으로 해석
  - 출력 숫자는 사용 가능한 모든 10진 자릿수로 표시
  - `Number.toString()` 사용
- 전체 정밀도 모드 비활성화 시 동작
  - 사용자가 입력한 숫자는 입력한 10진 표현에 가장 가까운 IEEE 754 값과 양 경계가 같은 **퇴화 구간**으로 해석
  - 출력 숫자는 최대 소수점 4자리로 표시
  - `Number.toPrecision()` 사용

### 버그
- 계산기에 아직 버그가 남아 있을 가능성 언급
- 문제 보고 경로로 GitHub 이슈 링크 제공

### 오픈소스
- **Interval Calculator**와 계산기 엔진 **not-so-float** 모두 오픈소스로 공개
- GitHub Sponsors 후원 링크 포함

### 향후 작업
- 전체 정밀도 모드를 두 개의 제어 항목으로 분리 예정
  - 입력 해석
  - 표시 정밀도
- `ans` 변수 추가 예정
  - 이전 입력 결과 저장 변수
- 교집합 연산자 또는 함수 추가 예정
- `U` 연산자 우선순위의 직관성 개선 예정
- 빈 합집합 입력 지원 예정

## Comments



### Comment 55806

- Author: neo
- Created: 2026-04-19T10:01:15+09:00
- Points: 1

###### [Hacker News 의견들](https://news.ycombinator.com/item?id=47812341) 
- 작성자로서 말하자면, **바깥쪽 반올림**은 정밀도 문제 대응으로 interval arithmetic에서 가장 유명하지만, 내 생각엔 그것만 주목받는 게 아쉬움. 연구 논문에서 말하는 **포함 성질**은 모든 스케일에서 작동하고, 그래서 `50 * (10 + [-1, 1]) = [450, 550]` 같은 결과가 자연스럽게 나옴. 여기에 union 레이어를 얹으면 제곱 함수의 진짜 역함수 같은 것도 다룰 수 있고, `sqrt`가 아니라 `sqinv(64)`를 해보면 느낌이 옴. 사실 이 interval calculator는 다른 프로젝트인 **backwards updating spreadsheet**를 위해 만들던 interval union arithmetic 구현을 시험하려고 만든 것이었음. 구현체는 [not-so-float](https://github.com/victorpoughon/not-so-float), 관련 프로젝트는 [bidicalc](https://victorpoughon.github.io/bidicalc/)와 [HN 토론](https://news.ycombinator.com/item?id=46234734)에 있음
  - 구현한 arithmetic이 **IEEE 1788** 표준과 어떻게 다른지 궁금함. 링크한 두 논문이 그 표준과 어떤 관계인지도 알고 싶음. 글에서 언급한 문제들을 해결하려면 완전히 새로 시작해야 했는지, 아니면 IEEE 표준 위에 쌓아 올릴 수 있었는지도 궁금함
  - 정말 멋져서 더 만져볼 생각임. 두 가지가 특히 궁금한데, 첫째로 **다가 함수**를 추가하기 얼마나 어려운지 궁금함. 예를 들어 `asin(1)`에서 Mathematica 없이도 `[pi/2, pi/2] + n[2pi, 2pi]` 전체 집합을 얻을 수 있으면 아주 좋겠음. 둘째로 사용자 입력 숫자를 해석하는 설명 문구가 좀 헷갈렸음. 내가 보기엔 입력값을 포함하는 가장 작은 구간의 **출력 경계값**이 입력값을 감싸는 가장 가까운 두 IEEE 754 수여야 할 것 같은데, 지금 문장대로면 `IEEE754(input)+[-epsilon, epsilon]`처럼 읽혀서 의미가 다르게 느껴졌음
- 이거 정말 좋음. **Matt Keeter**의 implicit surfaces 작업과 interval math를 이용한 최적화도 흥미롭게 볼 만함. [이 발표](https://youtu.be/UxGxsGnbyJ4?si=Oo6Lmc4ACaSr5Dk6&t=1006)에서 관련 내용을 확인할 수 있음
- 나도 **interval arithmetic**로 만든 그래핑 계산기가 있어서 관심 있을 것 같음. 직접 써볼 수 있는 [formulagraph](https://memalign.github.io/m/formulagraph/index.html)가 있고, 동작 방식과 관련 코드 설명은 [이 글](https://memalign.github.io/p/formulagraph.html)에 정리해뒀음
  - 첫인상이 **GrafEq**와 비슷하게 느껴졌음. 옛날 [GrafEq](http://www.peda.com/grafeq/)가 떠오름
- 나도 이게 재미있어서 Raku로 간단한 **Math::Interval** 라이브러리를 써본 적 있음. [raku-Math-Interval](https://github.com/librasteve/raku-Math-Interval)인데, Raku의 내장 **Junction**과 Range 클래스를 바탕으로 만든 실험이었고 꽤 흥미로운 경험이었음
- 아주 좋고 공유해줘서 고마움. interval에서 **상한·하한 포함 여부**를 표시해주면 더 좋겠다는 생각임. 내가 익숙한 표기법은 값이 포함되지 않을 때 바깥을 향한 괄호를 쓰고, 무한대에도 항상 그렇게 적용함. 예를 들면 `]-∞, -1] U [0.5, +∞[`처럼 쓰고, 중간의 제외 구간은 `]-1, 0.5[`가 됨. 내가 이해한 바로는 min과 max도 이런 식으로 해석되는 것 같음. 그리고 결과 영역의 수식을 클릭하거나 탭하면 입력창으로 복사되는 **UI 아이디어**도 있으면 편할 것 같음
  - 링크된 [논문](https://www.ime.usp.br/~montanhe/unions.pdf)을 읽어보니 여기서는 **닫힌 구간**만 설명하고 있었음. interval union은 닫혀 있고 서로 분리된 구간들의 집합이며, 양 끝 extreme interval의 경계만 ±∞가 될 수 있다고 정의되어 있었음
  - 그런 표기를 지원하는 건 가능하겠지만 코드가 **훨씬 복잡**해짐. 그래서 아주 이른 시점에 지원하지 않기로 결정했음. 그래도 멋진 추가 기능이 될 수는 있음
  - 나도 이 부분이 조금 헷갈렸음. 내가 알던 **표준 표기법**은 둥근 괄호였는데, 아마 ASCII 환경에서는 잘 안 맞을 수도 있겠다는 생각이 들었음
- 아주 멋짐. 모든 연산을 완전히 이해한 건 아니지만, 이해한 부분만으로도 꽤 인상적이었음. 수업에서 **구간에 대한 산술**을 좀 더 일찍 접했으면 좋았겠다는 생각이 듦. 기초 통계의 신뢰구간이나 이차방정식의 ±처럼 이미 비슷한 개념이 나오는데, 결과를 하나의 데이터처럼 이어서 계산하지 못하고 매번 ±의 두 값을 따로 처리하는 게 늘 좀 아쉬웠음. 물론 교사는 응용으로 빨리 돌아가고 싶어 하니 깊게 다루지 않는 이유는 이해함. 그래도 이런 대상에도 일반적인 산술이 가능하다는 힌트 정도는 있었으면 좋았겠음. 지금 보여준 건 그보다 훨씬 더 나아간 형태지만, interval을 자체적인 동작을 가진 데이터로 보는 관점이 말이 된다는 **검증**처럼 느껴졌음
- 예전에 Clojure로 시간 구간 라이브러리 **tick**을 처음 쓸 때 interval arithmetic를 알았더라면 좋았겠다는 생각임. 이 라이브러리에는 [Allen's Interval Algebra](https://en.wikipedia.org/wiki/Allen's_interval_algebra) 구현도 들어가 있고, 실무 계산에 유용한 **이산 구간 집합** 개념도 받아들였음. 예를 들어 어떤 해에 속하는 휴가 구간 집합을 계산하는 HR 업무 같은 데 잘 맞음. 나는 Allen의 작업 정도만 알고 있다가 이런 집합이 주는 장점을 우연히 발견한 셈이었음. 코드는 [juxt/tick](https://github.com/juxt/tick)에 있음
- 이 도구의 쓸모는 충분히 보이지만, 개인적으로는 **확률적 계산기**가 더 유용할 것 같다는 생각임. 예를 들어 `1 / [-1, 2]` 같은 결과는 어떤 값이 얼마나 그럴듯한지 알려주지 않고, 입력이 균등하다고 가정해도 출력은 분명 **균등분포**가 아닐 것 같음
- 나도 최근에 비슷한 걸 구현했는데, 관점은 **집합 소속성** 쪽이었음. 그래서 interval membership에 대한 완전한 Boolean 분석을 하려면 **여집합 연산**이 필요했음. 여기 구간들은 모두 닫힌 집합이라 여집합은 열린 구간이 되는데, 내 용도에서는 끝점 포함 여부가 중요하지 않아서 열린 구간과 닫힌 구간을 굳이 구분하지 않았음. 게다가 부정확한 산술에서는 집합이 열린지 닫힌지 자체가 잘 정의되지 않을 수도 있다고 봄
- union of intervals로 논리를 확장한 건 멋져 보이지만, **복잡도**가 궁금함. 어떤 연산 하나가 구간 두 개를 만들 수 있게 되면, N번 연산 시 경우에 따라 **지수적 증가**가 생길 것 같음. 그러면 일정 개수 이상에서 근사를 도입하지 않는 한 abstract interpretation 같은 흔한 활용에는 비현실적일 수 있겠다는 걱정임
  - 맞는 지적이고, 이런 문제는 **abstract interpretation** 쪽에서 잘 알려져 있음. 말한 것처럼 보통은 객체 크기에 cap을 두고 한도를 넘으면 구간들을 합쳐버리는 방식을 씀. 다만 적어도 abstract interpretation에서는 interval보다 더 **정교한 도메인**을 쓰는 경우도 많은 것 같음
