John Stagich's Blog

Microsoft .Net Developer

.NET Math.Round, MidPointRounding Overload

clock February 11, 2015 15:32 by author JohnStagich

I have been working with the Microsoft .NET framework for a while.  The other day I learned something new.  I was using the Math.Round method, and I noticed that it was not working the way that I expected.  Here is what I mean.  I had a value of .3650, and I was rounding it to two decimal places Math.Round(.3650,2).  I was expecting the result to round up to .37, but instead it rounded down to .36.  What's going on? 

After some research, I found that the Math.Round method in .NET, by default, follows the round-to-even rule or bankers rounding.  From MortgageLoanCalculating.com:

“In grade school most of us learned that when the remainder at the rounding position is .5 or above we round up and if less than .5 we round down. When dealing with small amounts of data, this rounding method does not present a problem. However, when working with large sets of numbers, this rounding method produces results that will be skewed upwards. To address this problem, a new rounding method, sans the asymmetrical frequency distribution, was developed.

“With the round-to-even rule, when the remainder at the rounding position is .5, that number is rounded up when the number before it is odd, and rounded down when the number before it is even. For example, the number 6.5, using the round-to-even rule, would round down to the even number 6.0, while the number 7.5 would round up to the even number 8.0 -- hence the name round-to-even rule. The round-to-even rule is also referred to as bankers rounding because, not surprisingly, this rounding method is often used by bankers.”

So in my case with Math.Round(.3650,2), since the number before .50 was even, 6, it rounded down to .36.  Not what I wanted.  The fix, the Math.Round method comes with an overload that takes a MidpointRounding value.

Using the overload Math.Round(.3650,2,MidPointRounding.AwayFromZero), my code returned .37, which was what I wanted.

Why does the Math.Round method default to the round-to-even rule or bankers rounding?  Apparently, it is following the IEEE 754 standard.

I also tried rounding .3650 to two decimal places using the T-SQL and Excel rounding functions.  In both cases, the result was .37. 

Below are links I used to gather my information.

http://msdn.microsoft.com/en-us/library/System.Math.Round(v=vs.110).aspx#Round3_Example

http://stackoverflow.com/questions/977796/why-does-math-round2-5-return-2-instead-of-3-in-c



Using the .NET ExpandoObject Class

clock February 4, 2015 14:37 by author JohnStagich

Background

On my current assignment at an aluminum company, I was working on a .NET/SQL Windows Forms application.  I was asked to dynamically add columns to a DataGridView like control (ComponentOne’s C1FlexGrid control). 

 

Before assigned this task, I was populating the grid with a generic list of objects: List<PricePageGrid>.

 

List<PricePageGrid>  pricePageGridList  = new List<PricePageGrid>();

 

public class PricePageGrid

{

    public string Alloy { get; set; }

    public string Shape { get; set; }

    public string Size { get; set; }

    public decimal BasePrice { get; set; }

    public string Weight { get; set; }

    public decimal PriceAdder { get; set; }

    public decimal PercentageAdjustment { get; set; }

    public decimal QuantityDiscountPrice { get; set; }

}

// Set the DataSource property of the grid to the pricePageGridList

PricePageGrid.DataSource = pricePageGridList;

 

I was then told that my PricePageGrid class now needed to accommodate a variable number of properties, which needed to be displayed in the grid.  More specifically, the class needed to accommodate a variable number of Temper Adders from a TemperAdderList, and for each item in the list, add a new property along with its value to the PricePageGrid object.  Below is some pseudo code that may help clarify what needed to be done.

 

public List<TemperAdder> TemperAdderList { get; set;}

 

public class PricePageGrid

{

    public string Alloy { get; set; }

    public string Shape { get; set; }

    public string Size { get; set; }

    public decimal BasePrice { get; set; }

    public string Weight { get; set; }

    public decimal PriceAdder { get; set; }

    public decimal PercentageAdjustment { get; set; }

    public decimal QuantityDiscountPrice { get; set; }

 

   // For each instance of the class, add a Temper Adder property along with its value for each TemperAdder item in the TemperAdderList.

    public object_type TemperAdder_1  {get; set; }  // Temper Adders 1 to N

    ...

    public object_type TemperAdder_N {get; set; }

}

Solution

 

After doing some research, I found the ExpandoObject class (System.Dynamic.ExpandoObject) in the .NET 4.0 Framework.  It represents an object that allows you to dynamically add and remove members at run time.  It was what I needed.  However, I quickly had a problem.  The example ExpandoObject code that I was copying into my application would not compile.  The fix: I needed to add a reference to the Microsoft.CSharp.dll to my project.

 

To make the ExpandoObject code readable, I found some code on the web from Jonathon Sullinger that neatly wraps some of the functionality of the ExpandoObject class.  Here is the code that I ended up with. 

 

public class DynamicPricePage

{

    public dynamic Instance = new ExpandoObject();

 

    public void AddProperty(string name, object value)

    {

        ((IDictionary<string, object>)this.Instance).Add(name, value);

    }

 

    public dynamic GetProperty(string name)

    {

        if (((IDictionary<string, object>)this.Instance).ContainsKey(name))

            return ((IDictionary<string, object>)this.Instance)[name];

        else

            return null;

    }

 

    public void AddMethod(Action methodBody, string methodName)

    {

        this.AddProperty(methodName, methodBody);

    }

}

 

Using the AddProperty() method in the DynamicPricePage class, I could easily add properties to the DynamicPricePage instance at runtime.  The next section will show you how.

Creating the Dynamic Object and Populating the List

 

1)       The code to create the dynamic object and set the “static” properties. 

Note: When assigning a value to a property, the property type becomes the type of the value.  So for instance, the type of the Weight property will be a string, because it was assigned a string value “0.0”.

 

        DynamicPricePage ppg                                           = new DynamicPricePage();

       

        ppg.Instance.Alloy                                                  = AlloyDescription;

        ppg.Instance.Shape                                                = ShapeDescription;

        ppg.Instance.Size                                                    = DimensionDescription

        ppg.Instance.BasePrice                                          = BasePricePerUOM;

        ppg.Instance.Weight                                              = “0.0”;

        ppg.Instance.PriceAdder                                       = 0.0m;

        ppg.Instance.PercentageAdjustment                  = 0.0m;

        ppg.Instance.QuantityDiscountPrice                   = ppg.Instance.BasePrice + PriceAdder;

 

2)       The code to dynamically add the variable number of properties along with their values from the TempeAdderList to the DynamicPricePage object.

 

        foreach (TemperAdder ta in TemperAdderList)

        {

                        ppg.AddProperty(ta.Description, ta.PriceAdder)  // property name and value

        }

 

3)       Add the dynamic object to a list of DyamicPricePage objects.

List<DynamicPricePage> pricePageGridList = new List<DynamicPricePage>();


pricePageGridList.Add(ppg);


Converting the List of Dynamic Objects to a Table

Now that I had the data that I wanted in a pricePageGridList, I assigned the pricePageGridList to the data source property of the grid: PricePageGrid.DataSource = pricePageGridList.  When I ran the application, no data appeared in the grid.  Why?  In short, the grid did not like the DynamicPricePage type of the pricePageGridList.

 

What next? The pricePageGridList was not of much use if I could not display its contents in the grid.  Could I convert the pricePageGridList to a table?  The answer, YES!


It was a three step process to convert the pricePageGridList to a table.  Here is the link where I found the code to convert the list of dynamic objects to a table.

 

1)       Cast a dynamic object to dictionary so we get the properties from it.

var dynamicPricePageProperties = pricePageGridList[0].Instance as IDictionary<string, object>;

 

2)       Create a DataTable and add columns to the table using the dynamicPricePageProperties acquired in step one.  Also, set the data type when adding a column.  In a table, if a column's data type is a string, you cannot apply a Format.  For example, pricePageGrid.Cols["BasePrice"].Format = "####0.00" will not work.

 

var table = new System.Data.DataTable();

foreach (var column in dynamicPricePageProperties)

{

if (Utility.IsDecimal(column.Value.ToString()))   // Utility.IsDecimal tries to parse the string: decimal.Parse(input);

table.Columns.Add(column.Key, typeof(decimal));

               else

                                table.Columns.Add(column.Key, typeof(string));

 }

3)       Populate the table created in step two using the pricePageGridList

 

              foreach (DynamicPricePage dynamicPricePage in pricePageGridList)

              {

                        DataRow row = table.NewRow();

                        System.Collections.Generic.IDictionary<string, object> dictionaryCollection =   dynamicPricePage.Instance as IDictionary<string, object>;

                        foreach (var key in dictionaryCollection.Keys)

                        {

                            row[key] = dictionaryCollection[key];   // Uses the key to retrieve the Value of the item in the dictionaryCollection                       

                        }

                        table.Rows.Add(row);

              }

 

Once I converted the list of dynamic objects into a table, I assigned the table to the DataSource property of the grid (PricePageGrid.DataSource = table;), and the data now appeared in the grid when I ran the application.



February 2014 Quick Hits

clock February 20, 2014 10:04 by author JohnStagich
  • I was having a problem with my HP Photosmart C7250 printer going offline and staying offline, even though the printer was powered on and the network connection was good.  Here is a link to a utility program from HP (HP Print and Scan Doctor) that fixed the problem.

  • Here is a link to a Visual Studio tool that will recursively collapse selected nodes in the Solution Explorer window.  This tool is handy when you have a Visual Studio solution with a lot of projects and folders.

  • Here is a link to a Visual Studio magazine article about a new Visual Studio 2013 add-in that allows you to search for code snippets from the cloud and then insert them into your code without leaving Visual Studio.  To download the add-in, follow this link.

  • I was working at a site that had a Microsoft SQL 2008 database that was local to the desktop, and was consuming a lot of disk space due to the size of the log file (.ldf) for the database.  Here are three steps to shrink the log file.

1) From within SQL Server Management Studio, right mouse click on the database and select Properties.  In the Database Properties dialog box pick Options.  In the Options dialog box change the recovery model for the database from Full to Simple, and click OK.

2) From within SQL Server Management Studio, right mouse click on the database, and select Tasks -> Shrink -> Files. In the Shrink File dialog box, set the File Type to Log, and click OK.

3) If you want, change the recovery model back to Full from Simple in the Database Properties -> Options dialog box.



December 2012 Quick Hits

clock December 21, 2012 08:55 by author JohnStagich

 

Here are two WPF gems I found on the Internet this month.

1) For me, one of the drawbacks of the MVVM architecture was the complexity involved generating a message/dialog box from the View Model.  I found this solution on the stackoverflow website that uses Func and Action delegates, which I believe, simplifies the process.

In my View Model:

// Declare the delegates

public Func<string, string, bool>   OkCancelDialog              { get; set; }

public Action<string, string>       MessageDialogInformation    { get; set; }

public Action<string, string>       MessageDialogError          { get; set; }

I

In my View loaded event, assign MessagBox.Show method to the delegates:

void View_Loaded(object sender, RoutedEventArgs e)

{

       var vm = new ViewModel(this);

vm.OkCancelDialog           = (msg, caption) => MessageBox.Show(msg, caption, MessageBoxButton.OKCancel) == MessageBoxResult.OK;

vm.MessageDialogInformation  = (msg, caption) => MessageBox.Show(msg, caption, MessageBoxButton.OK, MessageBoxImage.Information);

vm.MessageDialogError        = (msg, caption) => MessageBox.Show(msg, caption, MessageBoxButton.OK, MessageBoxImage.Error);        

       this.DataContext = vm;

}


In my View Model, call the delegates:

if (OkCancelDialog("Message", "Caption"))

    //do something if true

else

    //else do something if false

MessageDialogInformation("Information Message", "Caption"); 

MessageDialogError("Error Message", "Caption");

2) Here is a routine I found on codeplex to allow for only one instance of a WPF application: http://wpfsingleinstance.codeplex.com/

 

 

 

 

 

 

 



March 2012 Quick Hits

clock March 16, 2012 09:28 by author JohnStagich
  • Here is a link to SQL Server Data Type Mappings documentation that I found helpful in understanding how SQL data types map to .NET data types and what SQL DataReader typed accessor (e.g., GetString and GeBoolean) is needed to read a particular SQL data type from within .NET.

  • A good link on how the retrieve the Microsoft SQL rowversion/timestamp value from the standard IDataReader interface.  Below is how I implemented.

    byte[] rowVersionBuffer = new byte[8];
    dataReader.GetBytes(rowVersionField_OrdinalValue, 0, rowVersionBuffer, 8);  // rowversion storage size is 8 bytes.  timestamp is a synonym for rowversion.
    businessObject.RowVersion = rowVersionBuffer;

    // business object rowversion/timestamp property

    private byte[] _RowVersion
    public byte[] RowVersion
    {
       get { return _RowVersion;}
       set { _RowVersion = value; }
    }

  • jsfiddle  A tool to test HTML, CSS, and JavaScript.


.NET Compile Problem: Referenced assembly could not be resolved

clock March 6, 2012 10:31 by author JohnStagich

I was working on a Visual Studio 2010 VB.Net Windows Service application.  I added a reference to an in-house IO library and then used the Imports keyword to import the namespace from the referenced assembly.  IntelliSense recognized the namespace and I had access to the methods in the IO library.

I then tried to compile the application.  It failed.  My Imports statement for the IO library and the methods I used with that library generated error messages.  Along with the errors, I noticed a warning message.  The warning message provided the clue to the solution.  It mentioned that the referenced IO assembly could not be resolved because it had a dependency on System.Data.OracleClient.

Here is the link where I found the solution (thanks Xiaoyu!).  It turns out that when I added the new Windows Service project, the targeted framework was for the .NET Framework 4 Client Profile.  That framework does not include the System.Data.OracleClient.dll. 

The fix: Change the target framework to .NET Framework 4 (Project Properties -> Compile tab -> Advanced Compile Options… -> Target framework drop down).

 



January 2012 Quick Hits

clock January 13, 2012 11:38 by author JohnStagich
  • How to remove a .Net project/solution from Team Foundation Server (TFS) source code control?  From within Visual Studio 2010, File->Source Control->Change Source Control..., and then unbind the project/solution.  Here is the link where I found this information.


December 2011 Quick Hits

clock December 22, 2011 12:31 by author JohnStagich
  •  Here is another way to clear browser cache with Internet Explorer: F12, Ctrl+R

 

  • I wanted to include the build date in an "about" form for a Windows desktop application.  Below is code to get the build date of the application.

    ' Get Build Date information.

Dim _ExecutingAssemblyName As String = Assembly.GetExecutingAssembly.GetName().Name
Dim _ExecutingAssembly As Assembly = Assembly.GetExecutingAssembly

Try
  Dim _buildDate As Date = File.GetLastWriteTime(_ExecutingAssembly.Location)
  lblBuildDate.Text = lblBuildDate.Text +
" " + _ExecutingAssemblyName + ", " + _buildDate.ToString
Catch
 
lblBuildDate.Text = " Error trying to find Build Date."
EndTry

 

  •  Here is a link to a free interactive .NET tutorial from Motti Shaked.


July 2011 Quick Hits

clock July 29, 2011 13:00 by author johnstagich
  • Here is a link to David Padbury’s blog on using Isotope with Knockout.js.  Check it out!

  • This issue has been covered before in other blog posts, but I want to reiterate what you can do when you get the following error message when working with Microsoft SQL Server: The database could not be exclusively locked to perform the operation.  (I received this message when I tried to change the name of a database.)

A fix for this problem is to set the restrict access property of the database to a SINGLE_USER.  Next, make your change (In my case I changed the name of the database).  Followed by, setting the restrict access property back to MULTI_USER .

You can set the restrict access property through either T-SQL code or from SQL Server Management Studio.

T-SQL Code:

ALTER DATABASE [database_name] SET SINGLE_USER WITH ROLLBACK IMMEDIATE
ALTER DATABASE [database_name] SET MULTI_USER

SQL Management Studio:

Right mouse click on the database and select properties.  Under Select a page, click on Options.  Scroll down to the State Group and find the Restrict Access property and change its setting accordingly.

Here is the link where I found this fix.

  • A link to Orchard CMS.  Orchard CMS is a free, open source content management system that allows users to rapidly create web sites on the Microsoft ASP.NET platform. It is built on a flexible extensibility framework that enables developers and customizers to provide additional functionality through extensions and themes.



June 2011 Quick Hits

clock June 14, 2011 09:44 by author johnstagich
  • I had a request to have a company logo that was incorporated into a larger image contain a link to a new company website.  The solution: Create an HTML image map and refer to that image map in the <img> tag.  I used Paint.Net to get the coordinates of the logo for the coords attribute of the <area> tag.  For more details, follow this link.  Thanks Nebojsa Pajkic!
 

<map name="CompanyLogo">

  <area shape="poly" coords="32,92,89,65,147,96,87,122,48,114" href="http://NewCompanyWebSite.com" />

</map>

<img src="images/largeImageWithLogo.jpg"  usemap="#CompanyLogo">

  • Here is a link on how to optimize WPF performance.  Here is link for a performance profiling tool for WPF from MSDN.



About the author

I am the owner of Stagich Software Consulting.  Stagich Software Consulting specializes in developing Microsoft .Net/Microsoft SQL software applications.

 

Calendar

<<  November 2024  >>
MoTuWeThFrSaSu
28293031123
45678910
11121314151617
18192021222324
2526272829301
2345678

View posts in large calendar

Month List

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

Sign In