development

(inf + 0j) * 1이 inf + nanj로 평가되는 이유는 무엇입니까?

big-blog 2020. 9. 25. 08:02
반응형

(inf + 0j) * 1이 inf + nanj로 평가되는 이유는 무엇입니까?


>>> (float('inf')+0j)*1
(inf+nanj)

왜? 이것은 내 코드에서 불쾌한 버그를 일으켰습니다.

1곱셈 적 정체성 은 왜 주지 (inf + 0j)않습니까?


1먼저 복소수로 변환되고 1 + 0j, 이는 내지 An 후 리드 inf * 0A의 결과 곱셈 nan.

(inf + 0j) * 1
(inf + 0j) * (1 + 0j)
inf * 1  + inf * 0j  + 0j * 1 + 0j * 0j
#          ^ this is where it comes from
inf  + nan j  + 0j - 0
inf  + nan j

기계적으로 받아 들여진 대답은 물론 옳지 만 더 깊은 대답이 주어질 수 있다고 주장합니다.

첫째, @PeterCordes가 주석에서하는 것처럼 질문을 명확히하는 것이 유용합니다. "inf + 0j에서 작동하는 복소수에 대한 곱셈 동일성이 있습니까?" 즉, OP가 복잡한 곱셈의 컴퓨터 구현에서 약점을 보거나 개념적으로 불건전 한 것이 있는가inf+0j

짧은 답변:

극좌표를 사용하여 복잡한 곱셈을 배율 및 회전으로 볼 수 있습니다. 1을 곱하는 경우처럼 무한한 "팔"을 0도 회전 시키면 끝이 유한 한 정밀도로 배치 될 것으로 예상 할 수 없습니다. 따라서 실제로에는 근본적으로 옳지 않은 것이 있습니다 inf+0j. 즉, 무한대에 도달하자마자 유한 오프셋이 무의미 해집니다.

긴 대답 :

배경 :이 질문이 돌아가는 "큰 문제"는 숫자 체계를 확장하는 문제입니다 (실수 또는 복소수를 생각하십시오). 그렇게하기를 원하는 한 가지 이유는 무한의 개념을 추가하거나 수학자라면 "압축"하기 위해서입니다. 다른 이유도 있지만 ( https://en.wikipedia.org/wiki/Galois_theory , https://en.wikipedia.org/wiki/Non-standard_analysis ) 여기서는 관심이 없습니다.

원 포인트 압축

이러한 확장에 대한 까다로운 부분은 물론 이러한 새 숫자가 기존 산술에 적합하기를 원한다는 것입니다. 가장 간단한 방법은 무한대 ( https://en.wikipedia.org/wiki/Alexandroff_extension )에 단일 요소를 추가하고 0을 0으로 나눈 값과 동일하게 만드는 것입니다. 이것은 실수 ( https://en.wikipedia.org/wiki/Projectively_extended_real_line )와 복소수 ( https://en.wikipedia.org/wiki/Riemann_sphere )에서 작동합니다.

기타 확장 ...

원 포인트 압축은 간단하고 수학적으로 건전하지만 여러 무한대를 포함하는 "더 풍부한"확장이 추구되었습니다. 실제 부동 소수점 숫자에 대한 IEEE 754 표준에는 + inf 및 -inf ( https://en.wikipedia.org/wiki/Extended_real_number_line )가 있습니다. 자연스럽고 간단 해 보이지만 이미 우리가 https://en.wikipedia.org/wiki/Signed_zero 와 같은 것을 발명하고 농구를하도록 강요합니다.-0

... 복잡한 평면의

복잡한 평면의 1 개 이상의 inf 확장은 어떻습니까?

컴퓨터에서 복소수는 일반적으로 실수 부분과 허수 부분에 대해 하나씩 두 개의 fp 실수를 붙임으로써 구현됩니다. 모든 것이 유한 한 한 완벽하게 괜찮습니다. 그러나 무한대가 고려됨에 따라 상황이 까다로워집니다.

복잡한 평면은 자연적인 회전 대칭을 가지고 있으며 전체 평면에 e ^ phij를 곱하는 것은 phi 라디안 회전과 동일하므로 복잡한 산술과 잘 연결됩니다 0.

그 부록 G 것

이제 단순하게 유지하기 위해 복잡한 fp는 기본 실수 구현의 확장 (+/- inf, nan 등)을 사용합니다. 이 선택은 너무 자연스러워서 선택으로 인식되지 않을 수도 있지만 그것이 의미하는 바를 자세히 살펴 보겠습니다. 복잡한 평면의 확장에 대한 간단한 시각화는 다음과 같습니다 (I = 무한, f = 유한, 0 = 0).

I IIIIIIIII I

I fffffffff I
I fffffffff I
I fffffffff I
I fffffffff I
I ffff0ffff I
I fffffffff I
I fffffffff I
I fffffffff I
I fffffffff I

I IIIIIIIII I

그러나 진정한 복잡한 평면은 복잡한 곱셈을 고려하는 평면이므로 더 유익한 투영은

     III    
 I         I  
    fffff    
   fffffff   
  fffffffff  
I fffffffff I
I ffff0ffff I
I fffffffff I
  fffffffff  
   fffffff   
    fffff    
 I         I 
     III    

In this projection we see the "uneven distribution" of infinities that is not only ugly but also the root of problems of the kind OP has suffered: Most infinities (those of the forms (+/-inf, finite) and (finite, +/-inf) are lumped together at the four principal directions all other directions are represented by just four infinities (+/-inf, +-inf). It shouldn't come as a surprise that extending complex multiplication to this geometry is a nightmare.

Annex G of the C99 spec tries its best to make it work, including bending the rules on how inf and nan interact (essentially inf trumps nan). OP's problem is sidestepped by not promoting reals and a proposed purely imaginary type to complex, but having the real 1 behave differently from the complex 1 doesn't strike me as a solution. Tellingly, Annex G stops short of fully specifying what the product of two infinities should be.

Can we do better?

It is tempting to try and fix these problems by choosing a better geometry of infinities. In analogy to the extended real line we could add one infinity for each direction. This construction is similar to the projective plane but doesn't lump together opposite directions. Infinities would be represented in polar coordinates inf x e^{2 omega pi i}, defining products would be straightforward. In particular, OP's problem would be solved quite naturally.

But this is where the good news ends. In a way we can be hurled back to square one by---not unreasonably---requiring that our newstyle infinities support functions that extract their real or imaginary parts. Addition is another problem; adding two nonantipodal infinities we'd have to set the angle to undefined i.e. nan (one could argue the angle must lie between the two input angles but there is no simple way of representing that "partial nan-ness")

Riemann to the rescue

In view of all this maybe the good old one point compactification is the safest thing to do. Maybe the authors of Annex G felt the same when mandating a function cproj that lumps all the infinities together.


Here is a related question answered by people more competent on the subject matter than I am.


This is an implementation detail of how complex multiplication is implemented in CPython. Unlike other languages (e.g. C or C++), CPython takes a somewhat simplistic approach:

  1. ints/floats are promoted to complex numbers in multiplication
  2. the simple school-formula is used, which doesn't provide desired/expected results as soon as infinite numbers are involved:
Py_complex
_Py_c_prod(Py_complex a, Py_complex b)
{
    Py_complex r;
    r.real = a.real*b.real - a.imag*b.imag;
    r.imag = a.real*b.imag + a.imag*b.real;
    return r;
}

One problematic case with the above code would be:

(0.0+1.0*j)*(inf+inf*j) = (0.0*inf-1*inf)+(0.0*inf+1.0*inf)j
                        =  nan + nan*j

However, one would like to have -inf + inf*j as result.

In this respect other languages are not far ahead: complex number multiplication was for long a time not part of the C standard, included only in C99 as appendix G, which describes how a complex multiplication should be performed - and it is not as simple as the school formula above! The C++ standard doesn't specify how complex multiplication should work, thus most compiler implementations are falling back to C-implementation, which might be C99 conforming (gcc, clang) or not (MSVC).

For the above "problematic" example, C99-compliant implementations (which are more complicated than the school formula) would give (see live) the expected result:

(0.0+1.0*j)*(inf+inf*j) = -inf + inf*j 

Even with C99 standard, an unambiguous result is not defined for all inputs and it might be different even for C99-compliant versions.

Another side effect of float not being promoted to complex in C99 is that multiplyinginf+0.0j with 1.0 or 1.0+0.0j can lead to different results (see here live):

  • (inf+0.0j)*1.0 = inf+0.0j
  • (inf+0.0j)*(1.0+0.0j) = inf-nanj, imaginary part being -nan and not nan (as for CPython) doesn't play a role here, because all quiet nans are equivalent (see this), even some of them have sign-bit set (and thus printed as "-", see this) and some not.

Which is at least counter-intuitive.


My key take-away from it is: there is nothing simple about "simple" complex number multiplication (or division) and when switching between languages or even compilers one must brace oneself for subtle bugs/differences.


Funny definition from Python. If we are solving this with a pen and paper I would say that expected result would be expected: (inf + 0j) as you pointed out because we know that we mean the norm of 1 so (float('inf')+0j)*1 =should= ('inf'+0j):

But that is not the case as you can see... when we run it we get:

>>> Complex( float('inf') , 0j ) * 1
result: (inf + nanj)

Python understands this *1 as a complex number and not the norm of 1 so it interprets as *(1+0j) and the error appears when we try to do inf * 0j = nanj as inf*0 can't be resolved.

What you actually want to do (assuming 1 is the norm of 1):

Recall that if z = x + iy is a complex number with real part x and imaginary part y, the complex conjugate of z is defined as z* = x − iy, and the absolute value, also called the norm of z is defined as:

enter image description here

Assuming 1 is the norm of 1 we should do something like:

>>> c_num = complex(float('inf'),0)
>>> value = 1
>>> realPart=(c_num.real)*value
>>> imagPart=(c_num.imag)*value
>>> complex(realPart,imagPart)
result: (inf+0j)

not very intuitive I know... but sometimes coding languages get defined in a different way from what we are used in our day to day.

참고URL : https://stackoverflow.com/questions/58031966/why-does-inf-0j1-evaluate-to-inf-nanj

반응형