[[분류:프로그래밍 언어 문법]] [include(틀:관련 문서, top1=컴퓨터/표현)] [include(틀:프로그래밍 언어 문법)] [목차] == 개요 == {{{+2 '''Not a Number, NaN[* N이 2개 있지만 서로 다른 뜻이다.]'''}}} NaN은 잘못된 입력으로 인해 계산을 할 수 없음을 나타내는 기호이다. 이를테면 [[허수|음수의 제곱근]]을 구하려고 한다거나, 수만 나타낼 수 있는 변수에 텍스트를 넣었을때 일어나며, 일부 언어에서는 [[0으로 나누기|0으로 나눈 몫]]을 구하려고 할 때 예외를 던지는 대신 NaN을 반환하기도 한다. 이는 실수만을 저장할 수 있는 기본 [[부동소수점]] 저장체계에는 저장할 수 없는 허수나 실존하지 않는 수를 저장할 수 없기 때문에 오류 대신 반환하는 리턴값이다. [[JavaScript]]에서는 숫자와 문자를 연산하거나, 숫자가 아닌 수를 파싱하려 할 때 주로 리턴되며, [[Java]]에서는 [[부정형]][* 0 / 0, Infinity * 0, Infinity - Infinity, Infinity / Infinity 등. 물론 2의 1024제곱 이상의 모든 수는 무한으로 취급한다. 반대로 5e-324보다 작아지면 0으로 취급한다. 그리고 현재 값의 10경 분의 1도 안되는 값은 더하거나 빼는 건 아예 안 한 것과 같은 것으로 취급한다.]을 계산하려 하거나 Math 함수로 연산시 잘못된 값(제곱근 함수에 음수 입력 등)이 들어가면 주로 리턴된다. (자바스크립트에서 0이 아닌 숫자를 0으로 나누면 {{{Infinity}}}가 나오며, 자바에서도 double이나 float에서 0으로 나누면 동일한 결과가 나온다.[* 단, int 등 정수값의 경우 java.lang.ArithmeticException: / by zero 예외가 발생한다.]) 그리고 무한이라는 뜻은 아니다. 물론 무한으로 취급되는 경우가 많긴 하다. 하지만 어떤 경우에는 0보다 못한 음의 무한이 될 수도 있다. 만약 돈이 NaN이면 물건을 무한히 살 수 있지만 최소 0보다 커야 하는 값이 NaN이면 오히려 0만도 못하다. == 필요성 == 어떤 사람은 NaN 대신 [[예외#s-2]]를 던지는게 더 나을 것이라고 생각할 수도 있다. 하지만 꼭 그런것만은 아닌게 사용자가 입력을 한 값을 프로그램의 알고리즘에 대입을 했을 때 개발자가 예상치 못한 오류는 항상 생길 수 있으며 그럴 때마다 프로그램이 오류를 뿜으려 종료되는 것은 좋지 못하기 때문에 일단 프로그램은 잘 돌아가도록 NaN을 반환하는게 이득일 때도 있다. == 문제점 == 자바스크립트에서, NaN은 참 NaN인지 알아내기 어려운 값이다. {{{x == NaN}}} 같은 비교 연산으로 알아낼 수 있나 싶겠지만, {{{NaN == NaN}}}은 {{{false}}}가 나오는 것을 확인할 수 있고, 일치 연산자 [[===]]를 사용해도 {{{NaN === NaN}}}은 false가 나온다[* 역설적으로, 이걸 이용해 NaN을 구분하는 함수를 만들 수 있다! {{{#!syntax javascript const isNaN2 = _ => _ !== _ }}}]. 전역 함수로 isNaN()이 있지만, 이 함수는 정확히 말하면 '어떤 값이 숫자로 변환될 수 있는지'를 알려주는 함수인 데에다, [[Null|null]]을 {{{false}}}로 판단하는 등의 문제가 있었다. (이 문제는 [[ES6]]에서 {{{Number.isNan()}}}함수가 나오며 해결되었다.) 하지만 자바스크립트에선 여전히 마땅히 예외가 발생해야 할 이상한 연산에서도 NaN이 나오고 마는 경우가 있어 디버깅이 어려워지는 등의 문제가 있다. 수학적으로 보면 이 개념이 이상하게 보일 수 있다. [math(\sqrt{-0} = {\sf NaN})]이라면 말이 되는가?[* 수학적으로는 그냥 [math(0)]이다.] == 각종 언어에서의 NaN 예시 == * [[C\#]][* 다음 두 줄의 코드는 모두 NaN을 출력한다.] {{{#!syntax csharp Console.WriteLine(Math.Sqrt(-3)); Console.WriteLine(double.NaN); }}} * [[JavaScript]] {{{#!syntax javascript 33 - "a" // NaN parseInt("abc") // NaN 0 / 0 // NaN }}}--'b' + 'a' + + 'n' + 'a' // [[바나나|baNaNa]]-- * [[Java]] {{{#!syntax java System.out.println(0.0D / 0.0D); System.out.println(Double.NaN); }}} * [[Python]] {{{#!syntax python import numpy print(numpy.NaN) }}} * [[Swift]] {{{#!syntax swift let x = 1.21 let y = x + Double.nan print(y == Double.nan) print(y.isNaN) }}}상기 코드에서 "print(y == Double.nan)" 코드는 false를 내뱉지만, print(y.isNaN) 코드는 true를 출력한다. 일반적인 상황에서 Swift는 NaN 에러를 출력하지 않지만, {{{#!syntax swift .isNaN}}}을 변수명 뒤에 붙이는 것으로 해당 변수가 숫자인지, 숫자가 아닌지 Bool값을 출력할 수 있다. 숫자가 아니면 true, 숫자라면 false. 이렇게 복잡한 이유는, Swift는 NaN을 Float값의 하나로 처리하기 때문. [[https://developer.apple.com/documentation/swift/float/nan|코드 출처]] 이와 같은 논리로, 하기 코드도 NaN으로 인식된다. {{{#!syntax swift let number: Double = 0.0 / 0.0 print(number.isNaN) }}}다만, 일부 언어와 달리 단순 print(0/0)을 돌려도 NaN이 출력되지는 않고, print(0.0/0.0)을 실행해야 nan이 출력된다. 이 역시 상술했듯 Swift에서 NaN을 Int가 아닌 Float(혹은 Double)의 일환으로 처리하기 때문. 단순히 Int값으로 0/0을 출력하려고 하면 "error: division by zero"로 컴파일 에러가 발생한다.