Controlling the number of significant digits used by jsonencode - matlab

I'd like to use jsonencode in Matlab R2022a to encode a structure containing double precision values, like e.g.:
>> s = struct('a', sqrt(2))
s =
struct with fields:
a: 1.4142
>> jsonencode(s)
ans =
'{"a":1.4142135623730951}'
But I don't need all the digits and I'd like to keep the JSON file short, so I'd like to have an output like:
'{"a":1.414}'
There does not seem to have such an option in jsonencode, so I have tried to remove the less significant digits beforehand. Unfortunately there are random rounding errors:
>> s.a = round(s.a*10^3)*10^-3
s =
struct with fields:
a: 1.4140
>> jsonencode(s)
ans =
'{"a":1.4140000000000005}'
These errors do not occur all the time, but it seems that the deeper the struct the more often I have these rounding errors.
Then I have tried to use vpa, but it does not seem to be compatible with jsonencode:
>> s.a = vpa(s.a,4)
s =
struct with fields:
a: 1.414
>> jsonencode(s)
ans =
'{"a":{}}'
Now I'm out of options. Is it possible to get a clean JSON output with control over the significant digits using pure Matlab ?

I changed the way I round numbers by using a feature of the round function and it removed the random rounding approximations (probably due to the division by the power of 10):
>> s.a = round(s.a, 4, 'significant')
s =
struct with fields:
a: 1.414
>> jsonencode(s)
ans =
'{"a":1.414}'

Related

Mod function returns 0 for Matlab

I have a problem with the mod function output in Matlab. I am trying to perform some calculations for ECC double and add algorithm. I am reading data from a file and storing it in a variable and then performing some operations. All works smoothly except that I get 0 in temp1 when I use mod(X2,P). However if I put in values stored in X2(3.0323e+153) and P(1.1579e+77) on command window (mod( 3.0323e+153, 1.1579e+77)), I get the correct values. Can anyone please help me? Below is the part of script which is problematic.
P = hex2dec('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F');
line = fread(fileID,[1,67],'*char');
while ~feof(fileID)
PX = line(4:67);
X = hex2dec(PX);
X2 = X^2;
temp1= mod(X2 , P)
end
line = fread(fileID,[1,69],'*char');
end
fclose(fileID);
I think the problem lies with how you're initializing P. From the documentation for hex2dec (emphasis mine):
d = hex2dec('hex_value') converts hex_value to its floating-point integer representation. The argument hex_value is a hexadecimal integer stored as text. If the value of hex_value is greater than the hexadecimal equivalent of the value returned by flintmax, then hex2dec might not return an exact conversion.
And the value of flintmax is:
>> flintmax
ans =
9.007199254740992e+15
Quite a bit smaller than your value for P. In fact, if we use num2hex to look at the two ways you initialize P, you can see a clear difference:
>> P = hex2dec('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F');
>> num2hex(P)
ans =
4ff0000000000000
>> num2hex(1.1579e+77)
ans =
4fefffda293c30de
As it turns out, the inexact conversion done by hex2dec results in a number that evenly divides into 3.0323e+153, thus giving you a remainder of 0:
>> mod(3.0323e+153, P)
ans =
0
>> mod(3.0323e+153, 1.1579e+77)
ans =
8.795697942083107e+76

Is there any way to increase 'realmax' in MATLAB?

realmax on my machine is:
1.7977e+308
I know I have to write my code in a way to avoid long integer calculations, but is there any way to increase the limit?
I mean something like gmp library in C
You may find vpa (variable- precision arithmetic) helpful:
R = vpa(A) uses variable-precision arithmetic (VPA) to compute each element of A to at least d decimal digits of accuracy, where d is the current setting of digits.
R = vpa(A,d) uses at least d significant (nonzero) digits, instead of the current setting of digits.
Here's an example how to use it:
>> x = vpa('10^500/20')
ans =
5.0e498
Note that:
The output x is of symbolic (sym) type. Of course, you shouldn't convert it to double, because it would exceed realmax:
>> double(x)
ans =
Inf
Use string input in order to avoid evaluating large input values as double. For example, this doesn't work
>> vpa(10^500/20)
ans =
Inf
because 10^500 is evaluated as double, giving inf, and then is used as an input to vpa.

undefined result during formatting in hexadecimal form

I can't understand what is reason of following result
>> format hex
>> 10
ans =
4024000000000000
>> 12
ans =
4028000000000000
as i know this numbers should be written in hexadecimal format,but why such result?i have tried different variant for example like this
>> x=20;
>> format hex
>> x
x =
4034000000000000
if i will try different format
>> format long
>> x=10
x =
10
>> x=10.456
x =
10.456000000000000
it works nice, so what is problem?
Matlab is behaving absolutely correct, x=12 creates a 64 bit floating point number witch has the presented hexadecimal representation. What you probably want is:
>>uint32(12)
ans =
0000000c

Results not correct when using diff function in Matlab

I'm using the diff Matlab function to get the difference between two successive values. And as shown here in this vector nz in this link as shown in nz the difference between col 261 and 260 is -1342 but when I use this script the result of difference between this coloumns don't appear in the result dnz. So if anyone could advise why this is not working?
This is my attempt:
load('nz.mat');
dnz = diff(nz);
If you type class(nz) you see that your data is unit16. And MATLAB saturates the results when dealing with integer values, i.e. since 0 - 1342 is lower than zero (the smallest value in uint16) it returns zero:
>> dnz=diff(nz);
>> dnz(260)
ans =
0
If you convert it to a class that can accomodate -1342 like int16 you get
>> dnz = diff(int16(nz));
>> dnz(260)
ans =
-1342

Increase Hex2dec or dec2hex output range in Matlab

I have a strange problem with hex2dec function in Matlab.
I realized in 16bytes data, it omits 2 LSB bytes.
hex2dec('123123123123123A');
dec2hex(ans)
Warning: At least one of the input numbers is larger than the largest integer-valued floating-point
number (2^52). Results may be unpredictable.
ans =
1231231231231200
I am using this in Simulink. Therefore I cannot process 16byte data. Simulink interpret this as a 14byte + '00'.
You need to use uint64 to store that value:
A='123123123123123A';
B=bitshift(uint64(hex2dec(A(1:end-8))),32)+uint64(hex2dec(A(end-7:end)))
which returns
B =
1310867527582290490
An alternative way in MATLAB using typecast:
>> A = '123123123123123A';
>> B = typecast(uint32(hex2dec([A(9:end);A(1:8)])), 'uint64')
B =
1310867527582290490
And the reverse in the opposite direction:
>> AA = dec2hex(typecast(B,'uint32'));
>> AA = [AA(2,:) AA(1,:)]
AA =
123123123123123A
The idea is to treat the 64-integer as two 32-bit integers.
That said, Simulink does not support int64 and uint64 types as others have already noted..