Why does fprintf attach a negative sign to a zero?

Here is some code to set up the demonstration,
load data
fid = fopen('runsim.py','w');
rotation=[0,0,-GantryAngles(1)];
This next line verifies that rotation(3) is exactly equal to zero,
isZero = (rotation(3)==0)
isZero = logical
1
Nevertheless, when I do a formatted file print, the 3rd zero ends up printed to the file with a negative sign attached:
fprintf(fid, "vN_%d.set_rotation(%g, %g, %g, 'deg')\n",1, rotation);
type runsim.py
vN_1.set_rotation(0, 0, -0, 'deg')
Why does this happen?

 채택된 답변

dpb
dpb 2025년 12월 4일
이동: dpb 2025년 12월 4일
load data
%fid = fopen('runsim.py','w');
rotation=[0,0,-GantryAngles(1)];
fprintf("vN_%d.set_rotation(%g, %g, %g, 'deg')\n",1, rotation)
vN_1.set_rotation(0, 0, -0, 'deg')
rotation=[0,0,GantryAngles(1)];
fprintf("vN_%d.set_rotation(%g, %g, %g, 'deg')\n",1, rotation)
vN_1.set_rotation(0, 0, 0, 'deg')
MATLAB keeps signed zero internally and the various C i/o formatting honors it whereas the default command line format short is a prettified output that removes the minus.
There is a "+" flag that can be added to a format specifier to force the sign, but there isn't one to remove the minus; you would have to preprocess as does the internal command line output formatting to remove it.

댓글 수: 6

Matt J
Matt J 2025년 12월 5일
편집: Matt J 2025년 12월 5일
Thanks. I can somewhat appreciate the numerical applications of signed zero, but I don't really understand why formatted I/O would preserve it. Or at least why it would preserve it by default, and with no option to suppress it. It just forces you to do extra pre-processing to get rid of something which I think you would only rarely want.
dpb
dpb 2025년 12월 5일
편집: dpb 2025년 12월 5일
"..numerical applications of signed zero, but I don't really understand why formatted I/O would preserve it."
You'll have to ask Kernigan and Ritchie about that originally and bring it up to the C Standards Committee, ISO/IEC JTC 1/SC 22/WG 14, known as WG14, ("WG" --> Working Group) <vbg>
Similarly as to the numeric behavior other than that @Steven Lord noted MATLAB differs from the IEEE 754 Standard, the C i/o runtime libraries are part of the C libraries which are embedded in the C/C++ compilers which MATLAB follows with the extensions to handle vector arguments more generically.
Mathworks have done the prettification in the default command output format along with handling other edge cases, but haven't changed the behavior of the C formatting specifications. I've always complained that Mathworks should have kept with the original FORTRAN heritage of using the FORMAT syntax instead as well as maintaing column-major storage order. It would be so much neater to be able to write '10F10.3', say rather than repmat('%10.3f',1,10).
There's also IEEE 754-2008 (and IEEE 754-2019) section 5.12.1, "External character sequences representing zeros, infinities, and NaNs", which has this first paragraph (emphasis added.)
The conversions (described in 5.4.2) from supported formats to external character sequences and back that recover the original floating-point representation, shall recover zeros, infinities, and quiet NaNs, as well as non-zero finite numbers. In particular, signs of zeros and infinities are preserved.
Does the combination of sprintf and sscanf preserve the sign of zero?
x = -0
x = 0
fmt = '%g';
y = sscanf(sprintf(fmt, x), fmt)
y = 0
z = 1./y % -Inf if y is -0, +Inf if y is +0
z = -Inf
To check, let's look at the hex representations of x, y, and positive 0.
format hex
[x; y; +0]
ans = 3×1
8000000000000000 8000000000000000 0000000000000000
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
I'm using sprintf as the MATLAB version of convertToDecimalCharacter (from section 5.4.2 of the IEEE standard) and sscanf as convertFromDecimalCharacter.
[At a quick skim of IEEE 754-1984, I don't think it talks about converting to text and back again.]
Matt J
Matt J 2025년 12월 5일
편집: Matt J 2025년 12월 5일
Adherence to IEEE 754 is a bit beside the point, IMHO. Matlab's fprintf() wrapper and and other text writing functions could offer pre-processing options that get applied before the data gets passed into the underlying C\C++ version of fprintf(). As it stands currently, if I want to ensure that I'm writing .txt files with agnostic 0, I have to expend overhead in M-code doing things like,
A = sign(A).*abs(A);
writematrix(A)
The point is that the need to do things like sign(A).*abs(A) is a bit unfriendly to Matlab style coding where we're trying to minimize M-coded sweeps through arrays (Yes, I know I could write a simple MEX).
"if I want to ensure that I'm writing .txt files with agnostic 0, I have to expend overhead in M-code doing things like..."
It is simpler to add zero:
writematrix(0+A)
I agree with @Stephen23 that adding 0 is easier.
format long g
A = -0
A =
0
fprintf('%g %g\n', A, A+0)
-0 0

댓글을 달려면 로그인하십시오.

추가 답변 (2개)

fprintf('%g %g\n', 0, -0)
0 -0
Negative zero is represented differently than non-negative zero, This is because it is mathematically different:
fprintf('%g %g\n', 1/0, 1/-0)
Inf -Inf

댓글 수: 4

It doesn't seem to reliably have the mathematical properties you would expect, e.g.,
-0<0
ans = logical
0
isequal(-0,0)
ans = logical
1
-0<0
being true would imply that there is a positive value epsilon such that
-0+epsilon == 0
but there is no such positive value.
Also see the Wikipedia page for "signed zero".
Note that there is at least one behavior described in the Arithmetic section on that page where MATLAB differs from IEEE. As stated in the IEEE Compliance section on the sqrt page:
format hex
negativeZero = -0 % note the sign bit
negativeZero =
8000000000000000
positiveZero = 0
positiveZero =
0000000000000000
x = sqrt(negativeZero) % matches positiveZero not negativeZero
x =
0000000000000000
FYI the hypot, atan2, and power documentation pages also have IEEE Compliance sections. Hypot's involves combinations of NaN and Inf, atan2's involves combinations of +0 and -0, and power's involves some NaN cases.
Checking out sqrt I discovered realsqrt, which I'd never known about.
The error message for a real, negative input
try
realsqrt(-1)
catch ME
ME.message
end
ans = 'Realsqrt produced complex result.'
suggests realsqrt actually did a computation but caught the error on the result.
OTOH, with a complex input
try
realsqrt(-1+1i)
catch ME
ME.message
end
ans = 'Invalid argument at position 1. Value must be real.'
it seems like realsqrt does error checking on the input.

댓글을 달려면 로그인하십시오.

John
John 2025년 12월 5일

1 개 추천

I'll add that negative zero is part of the IEEE 754 spec for floating point numbers. This is not MATLAB-specific.

카테고리

도움말 센터File Exchange에서 App Building에 대해 자세히 알아보기

제품

릴리스

R2024b

태그

질문:

2025년 12월 4일

댓글:

2025년 12월 6일

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by