如何解决带符号零的问题?
How to resolve the issue with signed zero?
我现在才知道 'signed zeroes',因为我正在尝试处理复数。问题是:
PROGRAM sZ
IMPLICIT NONE
REAL(KIND(0.d0)),PARAMETER :: r=0.2
COMPLEX(KIND(0.d0)) :: c0
c0=(0.0,0.5); print*,sqrt(c0**2-r)
c0=(-0.0,0.5); print*,sqrt(c0**2-r)
END PROGRAM sZ
虚部符号改变。
(0.0000000000000000,0.67082039547127081)
(0.0000000000000000,-0.67082039547127081)
非常欢迎任何 instructions/suggestions 解决此问题。
你可以做这样的事情,所以一个带符号的(负)零被捕获并替换为零。
PROGRAM sZ
IMPLICIT NONE
REAL(KIND(0.d0)),PARAMETER :: r=0.2
COMPLEX(KIND(0.d0)) :: c0
REAL(KIND(0.d0)),PARAMETER :: i = -0.0
REAL(KIND(0.d0)),PARAMETER :: j = 0.5
REAL(KIND(0.d0)),PARAMETER :: zero = 0.0
if (i .EQ. 0) then
c0 = (zero, j); print*,sqrt(c0**2-r)
else
c0=(i, j); print*,sqrt(c0**2-r)
end if
END PROGRAM sZ
我设计了一个小技巧来删除这个 signed zeros。
PROGRAM sZ
IMPLICIT NONE
REAL(KIND(0.d0)),PARAMETER :: r=0.2
COMPLEX(KIND(0.d0)) :: c0,zero
zero=(0.0,0.0)
c0=(0.0,0.5); c0=c0+zero; print*,sqrt(c0**2-r)
c0=(-0.0,0.5); c0=c0+zero; print*,sqrt(c0**2-r)
END PROGRAM sZ
现在结果是一样的。 :)
不过,我想了解更多。什么时候需要符号零?
您看到的值来自中间步骤和 sqrt
内在规范。
最终结果取决于 sqrt
的参数值:因为结果有实部和结果虚部的符号 。
两个参数的虚部符号是什么? (0.,0.5)
和 (-0.,0.5)
平方的虚部在第一种情况下为正,在第二种情况下为负(预期实现有符号零)。减去实数不会影响对象虚部的符号,它成为 sqrt
.
的参数
在某种程度上,您得到的结果是正确的,因此唯一需要解决的问题是您对获得相同结果的期望。但是,考虑
implicit none
complex :: z1=(-1.,0.), z2=(-1.,-0.)
print*, z1==z2, SQRT(z1)==SQRT(z2)
end program
即使是正确的,也很容易看出为什么会造成混淆。如果我们不希望这种情况发生,我们可以强制任何零虚部为一个特定符号(例如,非负):
! Force imaginary part away from -0.
if (z%Im==0.) z%Im = 0.
(这个评论很有必要。)
我们可以使用 z%Im
指示符访问和设置复变量的虚部,但这对于一般表达式是不可能的。您可能想要创建一个更通用的函数:
implicit none
complex :: z1=(-1.,0.), z2=(-1.,-0.)
print*, z1==z2, SQRT(z1)==SQRT(z2)
print*, z1==z2, SQRT(design_0imag(z1))==SQRT(design_0imag(z2))
contains
pure complex function design_0imag(z) result(zp)
complex, intent(in) :: z
zp = z
if (zp%Im==0.) zp%Im = 0.
end function design_0imag
end program
如其他答案所示,有几种方法可以实现将 -0
替换为 0
的逻辑(保持其他值不变)。请记住,只有当结果纯属虚构时,您才会体验到这一点。
我现在才知道 'signed zeroes',因为我正在尝试处理复数。问题是:
PROGRAM sZ
IMPLICIT NONE
REAL(KIND(0.d0)),PARAMETER :: r=0.2
COMPLEX(KIND(0.d0)) :: c0
c0=(0.0,0.5); print*,sqrt(c0**2-r)
c0=(-0.0,0.5); print*,sqrt(c0**2-r)
END PROGRAM sZ
虚部符号改变。
(0.0000000000000000,0.67082039547127081)
(0.0000000000000000,-0.67082039547127081)
非常欢迎任何 instructions/suggestions 解决此问题。
你可以做这样的事情,所以一个带符号的(负)零被捕获并替换为零。
PROGRAM sZ
IMPLICIT NONE
REAL(KIND(0.d0)),PARAMETER :: r=0.2
COMPLEX(KIND(0.d0)) :: c0
REAL(KIND(0.d0)),PARAMETER :: i = -0.0
REAL(KIND(0.d0)),PARAMETER :: j = 0.5
REAL(KIND(0.d0)),PARAMETER :: zero = 0.0
if (i .EQ. 0) then
c0 = (zero, j); print*,sqrt(c0**2-r)
else
c0=(i, j); print*,sqrt(c0**2-r)
end if
END PROGRAM sZ
我设计了一个小技巧来删除这个 signed zeros。
PROGRAM sZ
IMPLICIT NONE
REAL(KIND(0.d0)),PARAMETER :: r=0.2
COMPLEX(KIND(0.d0)) :: c0,zero
zero=(0.0,0.0)
c0=(0.0,0.5); c0=c0+zero; print*,sqrt(c0**2-r)
c0=(-0.0,0.5); c0=c0+zero; print*,sqrt(c0**2-r)
END PROGRAM sZ
现在结果是一样的。 :)
不过,我想了解更多。什么时候需要符号零?
您看到的值来自中间步骤和 sqrt
内在规范。
最终结果取决于 sqrt
的参数值:因为结果有实部和结果虚部的符号
两个参数的虚部符号是什么? (0.,0.5)
和 (-0.,0.5)
平方的虚部在第一种情况下为正,在第二种情况下为负(预期实现有符号零)。减去实数不会影响对象虚部的符号,它成为 sqrt
.
在某种程度上,您得到的结果是正确的,因此唯一需要解决的问题是您对获得相同结果的期望。但是,考虑
implicit none
complex :: z1=(-1.,0.), z2=(-1.,-0.)
print*, z1==z2, SQRT(z1)==SQRT(z2)
end program
即使是正确的,也很容易看出为什么会造成混淆。如果我们不希望这种情况发生,我们可以强制任何零虚部为一个特定符号(例如,非负):
! Force imaginary part away from -0.
if (z%Im==0.) z%Im = 0.
(这个评论很有必要。)
我们可以使用 z%Im
指示符访问和设置复变量的虚部,但这对于一般表达式是不可能的。您可能想要创建一个更通用的函数:
implicit none
complex :: z1=(-1.,0.), z2=(-1.,-0.)
print*, z1==z2, SQRT(z1)==SQRT(z2)
print*, z1==z2, SQRT(design_0imag(z1))==SQRT(design_0imag(z2))
contains
pure complex function design_0imag(z) result(zp)
complex, intent(in) :: z
zp = z
if (zp%Im==0.) zp%Im = 0.
end function design_0imag
end program
如其他答案所示,有几种方法可以实现将 -0
替换为 0
的逻辑(保持其他值不变)。请记住,只有当结果纯属虚构时,您才会体验到这一点。