Discover MakerZone

MATLAB and Simulink resources for Arduino, LEGO, and Raspberry Pi

Learn more

Discover what MATLAB® can do for your career.

Opportunities for recent engineering grads.

Apply Today

Thread Subject:
floating point help!

Subject: floating point help!

From: bogfrog

Date: 24 Jun, 2010 02:25:26

Message: 1 of 11

Hello,

I'm having an FP issue that's sort of driving me crazy. I'm doing some division by 10, subtracting, and taking a floor. Purely mathematically, this is exactly what I want to do:
------
num = 12;
a = num/10;
b = floor(a);
c = a-b;
d = 10*c;
finalResult = floor(d);
------

However, these are the results I get:

------
a = num/10 = 1.2000000000000000
b = floor(a) = 1.0000000000000000
c = a - b = 0.2000000000000000
d = 10*c = 1.9999999999999996
Final Result = floor(d) = 1.0000000000000000
------

But obviously, what I'm expecting mathematically is for the final result to be 2, not 1!

I know FP gets tricky this way... But is there anyway around this?

Basically, I'm doing this because I want to create a function that turns a number such as 3813919 into the array [3 8 1 3 9 1 9], and this was part of solving that problem (ie, decomposing a number into its digits). So if you have a good Matlab solution for that problem, that would also be a help.

I figured out an algorithm that would do this decomposition, but the FP precision screws everything up!

Thanks!


fprintf('a = num/10 = %.16f\n', a);
fprintf('b = floor(a) = %.16f\n', b);
fprintf('c = a - b = %.16f\n', c);
fprintf('d = 10*c = %.16f\n', d);
fprintf('Final Result = floor(d) = %.16f\n', finalResult);

Subject: floating point help!

From: Matt Fig

Date: 24 Jun, 2010 03:35:05

Message: 2 of 11

Use round on the last step;

Subject: floating point help!

From: dpb

Date: 24 Jun, 2010 03:54:18

Message: 3 of 11

bogfrog wrote:
...

> Basically, I'm doing this because I want to create a function
> that turns a number such as 3813919 into the array [3 8 1 3 9 1 9], ...

...

How about letting the i/o subsystem do it for you???

 >> digits=strread(sprintf('%d',3813919),'%1d')'
digits =
      3 8 1 3 9 1 9
 >>

--

Subject: floating point help!

From: Roger Stafford

Date: 24 Jun, 2010 03:59:05

Message: 4 of 11

bogfrog <aj00mcgraw@gmail.com> wrote in message <639153510.18073.1277346358514.JavaMail.root@gallium.mathforum.org>...
> Hello,
>
> I'm having an FP issue that's sort of driving me crazy. I'm doing some division by 10, subtracting, and taking a floor. Purely mathematically, this is exactly what I want to do:
> ------
> num = 12;
> a = num/10;
> b = floor(a);
> c = a-b;
> d = 10*c;
> finalResult = floor(d);
> ------
>
> However, these are the results I get:
>
> ------
> a = num/10 = 1.2000000000000000
> b = floor(a) = 1.0000000000000000
> c = a - b = 0.2000000000000000
> d = 10*c = 1.9999999999999996
> Final Result = floor(d) = 1.0000000000000000
> ------
>
> But obviously, what I'm expecting mathematically is for the final result to be 2, not 1!
>
> I know FP gets tricky this way... But is there anyway around this?
>
> Basically, I'm doing this because I want to create a function that turns a number such as 3813919 into the array [3 8 1 3 9 1 9], and this was part of solving that problem (ie, decomposing a number into its digits). So if you have a good Matlab solution for that problem, that would also be a help.
>
> I figured out an algorithm that would do this decomposition, but the FP precision screws everything up!
>
> Thanks!
>
>
> fprintf('a = num/10 = %.16f\n', a);
> fprintf('b = floor(a) = %.16f\n', b);
> fprintf('c = a - b = %.16f\n', c);
> fprintf('d = 10*c = %.16f\n', d);
> fprintf('Final Result = floor(d) = %.16f\n', finalResult);
- - - - - - - - - -
  Change your procedure just a little:

 num = 749;

 % Repeat this until num is zero
 b = floor(num/10);
 d = num-10*b; % The least tens' digit
 num = b;

This way you will not suffer round off error.

Roger Stafford

Subject: floating point help!

From: Jan Simon

Date: 24 Jun, 2010 10:28:07

Message: 5 of 11

Dear bogfrog,

> > Basically, I'm doing this because I want to create a function
> > that turns a number such as 3813919 into the array [3 8 1 3 9 1 9], ...
>
> dpd:
> >> digits=strread(sprintf('%d',3813919),'%1d')'
> digits =
> 3 8 1 3 9 1 9

Or simpler:
  digits = sprintf('%d', 3813919) - '0';
This does an implicte conversion to DOUBLE, but I'd prefer to perform this manually to be compatible with future Matlab versions:
  digits = double(sprintf('%d', 3813919) - '0');

Jan

Subject: floating point help!

From: Steven Lord

Date: 24 Jun, 2010 14:25:08

Message: 6 of 11


"bogfrog" <aj00mcgraw@gmail.com> wrote in message
news:639153510.18073.1277346358514.JavaMail.root@gallium.mathforum.org...
> Hello,
>
> I'm having an FP issue that's sort of driving me crazy. I'm doing some
> division by 10, subtracting, and taking a floor. Purely mathematically,
> this is exactly what I want to do:

*snip*

> But obviously, what I'm expecting mathematically is for the final result
> to be 2, not 1!
>
> I know FP gets tricky this way... But is there anyway around this?

Nope.

> Basically, I'm doing this because I want to create a function that turns a
> number such as 3813919 into the array [3 8 1 3 9 1 9], and this was part
> of solving that problem (ie, decomposing a number into its digits). So if
> you have a good Matlab solution for that problem, that would also be a
> help.

Avoid doing calculations on non-flints at all.

x = 3813919;
onesDigit = mod(x, 10); % x is flint, 10 is flint, so onesDigit is flint
x = x-onesDigit; % flint-flint calculation; result is a flint multiple of 10
x = x/10; % no roundoff involved
% repeat

To preallocate your results array, you'd probably want to use
ceil(log10(x)), or simply assume you don't have more than 20 digits [for
intmax('uint64')] or (since your numbers are going to be small) grow the
array in the loop and FLIPLR it at the end. Yes, I know growing an array in
the loop is inefficient. But since the loop is very short, you're not going
to be reallocating memory that often.

On the plus side, the algorithm above also works with variables of integer
classes.

x = uint32(3813919);
nextDigit = 1;
digitVector = zeros(1, 21); % give some wiggle room
while x > 0
    onesDigit = mod(x, 10);
    x = (x-onesDigit)/10;
    digitVector(nextDigit) = onesDigit;
    nextDigit = nextDigit+1;
end
digitVector = digitVector(nextDigit-1:-1:1);

--
Steve Lord
slord@mathworks.com
comp.soft-sys.matlab (CSSM) FAQ: http://matlabwiki.mathworks.com/MATLAB_FAQ
To contact Technical Support use the Contact Us link on
http://www.mathworks.com

Subject: floating point help!

From: bogfrog

Date: 24 Jun, 2010 14:43:36

Message: 7 of 11

>digits = double(sprintf('%d', 3813919) - '0');

This works beautifully, but what in the world is going on?

How does subtracting '0' turn this into an array of digits?

Subject: floating point help!

From: dpb

Date: 24 Jun, 2010 15:03:22

Message: 8 of 11

bogfrog wrote:
>> digits = double(sprintf('%d', 3813919) - '0');
>
> This works beautifully, but what in the world is going on?
>
> How does subtracting '0' turn this into an array of digits?

The sprintf() has already turned it into an array of characters; the
subtraction does an implicit conversion back to numeric by ML design.
Look at the results in the command window of the pieces of the
expression individually to see what happens each step.

It's an historic ML idiom; I just kinda like the explicit recast via the
strread() as opposed to the above. AFAICT it's personal preference
although it's undoubtedly documentably faster by the numerical operation
by avoiding the internal i/o. But, unless one has a _very_ deep loop or
somesuch it's highly unlikely to be discernible.

--

Subject: floating point help!

From: us

Date: 24 Jun, 2010 18:38:05

Message: 9 of 11

bogfrog <aj00mcgraw@gmail.com> wrote in message <1675532262.20705.1277390646666.JavaMail.root@gallium.mathforum.org>...
> >digits = double(sprintf('%d', 3813919) - '0');
>
> This works beautifully, but what in the world is going on?
>
> How does subtracting '0' turn this into an array of digits?

a hint:
- the DOUBLE typecast is not neccessary

     d=sprintf('%d',1357)-'0' % <- or -48, ie, ASCII rep of CHAR '0'
% d = 1 3 5 7
% and the rather trivial trick behind it...
     c=sprintf('%d',8)
% c = 8
% -or- its ASCII rep
     a=sprintf('%d - %d',c,'0')
% a = 56 - 48
% thus,
     56-48
% ans = 8

us

Subject: floating point help!

From: Jan Simon

Date: 24 Jun, 2010 21:37:04

Message: 10 of 11

Dear us,

> a hint:
> - the DOUBLE typecast is not neccessary

Correct. I'm sheepish since Matlab changed the results:
  Matlab 6.5: 'a':'c' => [97, 98, 99]
  Matlab 7.?: 'a':'c' => 'abc'
Casting a DOUBLE to DOUBLE is really fast, so I prefer to cast the result of operations with CHARs explicitely.

Jan

Subject: floating point help!

From: Steven Lord

Date: 24 Jun, 2010 22:02:08

Message: 11 of 11


"Jan Simon" <matlab.THIS_YEAR@nMINUSsimon.de> wrote in message
news:i00j60$f5o$1@fred.mathworks.com...
> Dear us,
>
>> a hint:
>> - the DOUBLE typecast is not neccessary
>
> Correct. I'm sheepish since Matlab changed the results:
> Matlab 6.5: 'a':'c' => [97, 98, 99]
> Matlab 7.?: 'a':'c' => 'abc'

According to the Release Notes, that change happened in MATLAB 7.5 (release
R2007b).

http://www.mathworks.com/access/helpdesk/help/techdoc/rn/bq9yg49-1.html#bq_7b6p

--
Steve Lord
slord@mathworks.com
comp.soft-sys.matlab (CSSM) FAQ: http://matlabwiki.mathworks.com/MATLAB_FAQ
To contact Technical Support use the Contact Us link on
http://www.mathworks.com

Tags for this Thread

What are tags?

A tag is like a keyword or category label associated with each thread. Tags make it easier for you to find threads of interest.

Anyone can tag a thread. Tags are public and visible to everyone.

Contact us