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?

 Akzeptierte Antwort

dpb
dpb am 4 Dez. 2025
Verschoben: dpb am 4 Dez. 2025
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 Kommentare

Matt J
Matt J am 5 Dez. 2025
Bearbeitet: Matt J am 5 Dez. 2025
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 am 5 Dez. 2025
Bearbeitet: dpb am 5 Dez. 2025
"..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 am 5 Dez. 2025
Bearbeitet: Matt J am 5 Dez. 2025
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

Melden Sie sich an, um zu kommentieren.

Weitere Antworten (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 Kommentare

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.

Melden Sie sich an, um zu kommentieren.

John
John am 5 Dez. 2025

1 Stimme

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

Kategorien

Mehr zu MATLAB Coder finden Sie in Hilfe-Center und File Exchange

Produkte

Version

R2024b

Tags

Gefragt:

am 4 Dez. 2025

Kommentiert:

am 6 Dez. 2025

Community Treasure Hunt

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

Start Hunting!

Translated by