Hi,
I working on a fairly large project in C#, combining numerous components such as SQL and DirectX.
We all, however, seem to have come across a severe problem! We can't do basic arithmetic!
For example, in VS.NET 2003, I need to subtract two UTC style time values - eg 11565456546546.1342345566 etc.
double large_val1, large_val2;
...
double difference = large_val1 - large_val2;
Instead of the result I expect (and indeed the result shown in the Watch window during debug for large_val1 - large_val2), I get a servely rounded value instead - that is entirely useless!! Help!! I can do this in a standard command line / console application and everything works fine - why should there be any difference ! I have tried decimal, seperating mantissa with fractional part, and so forth, yet always the same problem.
Any ideas
thanks in advance,
Ben Walker

Inaccurate/Wrong calculations
seu
thanks for the response
it's a weird one though - changing the way doubles behave without any form of huge warning is sort of dangerous! I've changed the flag and it all seems to work.
benw
Ashok Karmani
Okay, I agree that over the course of seconds since 1970, a few 100ths of milliseconds may be acceptable... however, here's another one -
http://www.benwalkermusic.co.uk/pics/sums2.JPG
Apparently 1153221506 + 33 = 1153221504. It looks like it's wrapping around something, yet if I try with ints and then recast back to doubles, I still get 1153221504...
Garrett Serack - MSFT
However, can you post an entire self-contained method that exhibits the problem (i.e. one that someone else can drop into a project and try)
gg1
There is nothing "wrong" with the answer you are getting. Both differences are exact -- to the precision of the operands. Do the subtraction yourself on paper if you like.
1153221555.7980 - 1153221506.7907 is exactly 49.0073. Both value you see are that value. Both include some meaningless "insignificant digits" which is an artifact to floating point math on computers, particularly when producing a small number by subtracting two large close numbers.
Now, what exactly do these number represent If the numbers are standard DateTime value (representing days & fractions of days), you are arguing over a tenth of a second in 300,000 years!
kevin delafield
I think it's partly to do with the scale of the numbers I'm using.
If I assign the difference to a new variable, I get the wrong number, however the difference in the 'Watch' window is the correct number.
I'm going to try breaking it up into ints and doubles to keep the precision in both integer and decimal parts - not at the desk at the moment so will try again tomorrow...
benw
stephenl
ruckycharms
Tyler M
Screenshot posted at
http://www.benwalkermusic.co.uk/pics/sums.JPG
FWIW I've tried converting my UTC Times back to DateTime structures and then calculating the difference, however the returned TimeSpan structure claims that the difference is zero...
Naveeeen
Nailed the source of the problem, but no solution: It's DirectX... Add references as neccessary
using System;
using System.Drawing;
using System.Windows.Forms;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;
using Direct3D=Microsoft.DirectX.Direct3D;
namespace SumTest
{
public class Test : Form
{
Device device = null; // Our rendering device
PresentParameters presentParams = new PresentParameters();
private System.Windows.Forms.Panel panel1;
private System.Windows.Forms.Label label1;
private IntPtr handle;
bool pause = false;
public Test()
{
InitializeComponent();
this.Text = "How not to add up";
}
public bool InitializeGraphics()
{
handle = this.panel1.Handle;
try
{
presentParams.Windowed=true;
presentParams.SwapEffect = SwapEffect.Discard;
device = new Device(0, DeviceType.Hardware, handle, CreateFlags.SoftwareVertexProcessing, presentParams);
pause = false;
return true;
}
catch (DirectXException)
{
return false;
}
}
private void Render()
{
label1.Text = CalcNumber().ToString("0.000000000");
if (device == null)
return;
device.Clear(ClearFlags.Target, System.Drawing.Color.White, 1.0f, 0);
device.BeginScene();
device.EndScene();
device.Present(handle);
}
private double CalcNumber()
{
double d1 = 1153221506.123456;
double d2 = 32.9565461;
return d1+d2;
}
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
this.Render(); // Render on painting
}
protected override void OnKeyPress(System.Windows.Forms.KeyPressEventArgs e)
{
if ((int)(byte)e.KeyChar == (int)System.Windows.Forms.Keys.Escape)
this.Close(); // Esc was pressed
}
protected override void OnResize(System.EventArgs e)
{
pause = ((this.WindowState == FormWindowState.Minimized) || !this.Visible);
}
private void InitializeComponent()
{
this.panel1 = new System.Windows.Forms.Panel();
this.label1 = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// panel1
//
this.panel1.Location = new System.Drawing.Point(8, 8);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(416, 392);
this.panel1.TabIndex = 0;
//
// label1
//
this.label1.Location = new System.Drawing.Point(40, 424);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(368, 23);
this.label1.TabIndex = 1;
this.label1.Text = "label1";
//
// Matrices
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(432, 469);
this.Controls.Add(this.label1);
this.Controls.Add(this.panel1);
this.Name = "Matrices";
this.ResumeLayout(false);
}
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main()
{
using (Test frm = new Test())
{
frm.Show();
if (!frm.InitializeGraphics()) // Initialize Direct3D
{
MessageBox.Show("Could not initialize Direct3D");
return;
}
// While the form is still valid, render and process messages
while(frm.Created)
{
frm.Render();
Application.DoEvents();
}
}
}
}
}
If you comment out the Graphics Initialisation code, the answer is correct. Surely there must be other people using DirectX and doubles that have had this problem I'm reposting this on the DX forum too, so hopefully someone will have some ideas...
William Lowers
I'm running in from within the debugger - I copy the variables/expressions into the watch window below to check what's going on. As the values are assigned, the value appears at the side of the variable/expression name.
There is no Console.ToString or similar that I call directly - it's whatever the watch window uses for it's formatting (afaik 16 decimal places). I'm simply trying to debug some code that does a quick linear interpolation between two UTC timestamps in double format. The problem arises when I try to calculate the difference in the two timestamps - wherby the answer never seems to be 'correct'. I'll try and post a screenshot tomorrow from the desk.
Suganya Mahadevan
Essentially, when creating a DirectX object, you should use the CreateFlags.FpuPreserve flag to keep the CLR's double precision.