|
You are possibly mixing float s and double s in there: we can't see the definition of the force or filter arrays, but the casting kinda implies the type.
So if force is an array of float values, then when you do this:
filter[0] = (float) (force[0] + 0.0 + filter[2]); The system is obliged to implicitly cast the force elements to double in order to do the addition, and that may be what is causing imprecision, and thus an error (we can't tell what you should have or what you get, so "NOT WORKING" isn't particularly helpful!)
You could try keeping it all in float values and see if that helps:
filter[0] = (float) (force[0] + 0.0F + filter[2]);
If not, then you need to use the debugger to find out what values exist in the force array, and what values you actually get / expect as a result.
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
"Common sense is so rare these days, it should be classified as a super power" - Random T-shirt
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
Ok
What looks so strange to me is anyhow why when I use 0.0001 instead of 0.0 I do not have the problem , (I tried also with other numbers and some give the problem, others do not).
Again, why the formula of the sine wave runs apparently correctly.
OK when I say working I mean apparently working without defects behaving like it is expected to.
Ex. I press the button, I read the pulse value back in the form after that SyncWrite transmitted to PLC , PLC trasferred to another tag, and form read back the new tag with the correct value
When I say not working I mean that strange behaviour that while pressing value is not transferred at all to the PLC (or at least it seems) or in other cases sometimes it is transferred and sometimes not .
This also followed by occasionally popup error windows telling about access violation when executing the SyncWrite.
Both Force and Filter arrays are declared float so in my opinion (just an opinion) the "true" filter algorithm should be ok, unless anytime I multiply or divide a mix of double and float is generated.
Debugging I look inside the value of the arrays and I can only see decimal numbers with comma so I cannot distinguish if they are float or double. Is there a way for this?
Thanks very much
|
|
|
|
|
When you mix float and double in the same expression, they have to "equalized" so you are working with the same type of values - much like when you multiply an integer by floating point value, you need to return a float in order to have any accuracy: 13 * 0.6 = 7.8 if you convert the integer to a float, but 13 * 0.6 = 0 if you convert the float to an int!
And a "normal" floating point constant is always a double unless you add the 'F' suffix to make it a float
And the implicit casting that the system does is always "upwards": byte to int, int to float or double, float to double, never the other way around.
So the float values in your array are converted to double values, multiplied by a double constant, and the result is cast - by you - back to a float .
And the problem is that numbers aren't stored in decimal: they are stored in binary (technically in IEEE-754 floating-point standard) and some values just don't "store well": What Every Computer Scientist Should Know About Floating-Point Arithmetic[^]
When you start converting from one floating point size to another, these problems can become exacerbated - which is why the decimal type exists to "reduce the precision" and make things more accurate as a result!
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
"Common sense is so rare these days, it should be classified as a super power" - Random T-shirt
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
So you think that a solution is to use decimal type? Or even this could have the same problem? At the end I will have to solve this, so if the only way is example to use integers (fixed comma) I can do that.
What is your suggestion?
Just for curiosity, this type of problem is relevant only to float type or also to double?
Thanks
Regards
|
|
|
|
|
Doubles and floats have the same problem: for example 0.1 and 0.2 can't be stored in a floating point format because they are a recurring number in binary, so 0.1 + 0.2 != 0.3 :
float fp1 = 0.1F;
float fp2 = 0.2F;
string result = (fp1 + fp2) == 0.3F ? "Yes" : "No";
Debug.WriteLine($"{fp1} + {fp2} = 0.3? {result}");
double dp1 = 0.1;
double dp2 = 0.2;
result = (dp1 + dp2) == 0.3 ? "Yes" : "No";
Debug.WriteLine($"{dp1} + {dp2} = 0.3? {result}");
Will give you:
0.1 + 0.2 = 0.3? No
0.1 + 0.2 = 0.3? No
I suspect that decimal may help, but to be honest I have no idea what you are trying to achieve, or what values you are actually looking at and expecting, do I can't recommend them as a "fix".
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
"Common sense is so rare these days, it should be classified as a super power" - Random T-shirt
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
My goal is only to pass to a RsiOpc.dll (from Rockwell) routine SyncWrite a number (or an array of them) that have only to be transferred to a PLC.
When I used integers i never had a problem. Now I would like to use decimal (I simply mean numbers with comma).
Then as I said I used also (what follows I took from the code directly, the samples I posted before are translated from italian where array_to_send is array_da_inviare)
r.array_da_inviare_D[0] = (float)(2 * Math.Cos((2 * (1.0 / periodo_sinusoide[0]) * Math.PI) * sec_tot));
Why this doesn't generate the problem? There are decimal,integers mixed and the result is a double as you say and in fact I converted everything to float to pass the value to array_da_inviare[0]
What I need to do is, instead of a sine wave, send just a value (at any cycle) that is the result of a second order filter
The filter formula is coming from its Laplace representation in S then passes into the discrete transformation Z and at the end becomes a quite easy formula being an algebric sum of some variables multiplied by some factors and divided by other factors. The result is simply another number that must transitate to a PLC. The real formula is exactly that of the second sample code. Just nothing more than this.
Meanwhile I convered filter and force array from float to decimal. So now code is:
decimal filter_result;
filter_result = filter();
r.array_da_inviare_D[0] = (float) (filter_result);
but also this way I have the problem
modified 19-Feb-21 8:36am.
|
|
|
|
|
Ok
I tested a bit different version where when I press the button which generates the pulse, this pulse doesn't go only to the PLC and is read back with the SyncRead but first of all goes directly to force[0]
then it is also copied to array_to_send[1] in order to be trended by the plc and as ever it is read back in the form. But main point here is that force[0] is fed directly with the pulse.
This way seems to be working using the correct formula for the second order filter unless some error messages coming sometimes with no evident frequency, not very often. Message, as I said in the previous posts, tells about access violation executing the SyncWrite.
This is interesting in my opinion since can be a sign of something going wrong in the very first moment of the filtering function when probably values inside the two arrays force and filter lead tio some mathematical error not well managed in the treatment of the float type if the force[0] is fed with the SyncWrite /SyncRead. While when it is fed directly probably numbers in the two arrays assess in a way that doesn't cause problems.
Could it be?
While
|
|
|
|
|
Even if the numbers of this elaboration are quite small (inthe sense that the force that I apply is in the unit order like 1, 2, 3 ,4 .... and the parameters of the filters lead to other small numbers and so the data to exchange with the SyncWrite are small (example < 10) the only way I found is to divide this number by 1 million within the c# code and then on the PLC side multiply by 1 million. (1 million is the best solution I found. I tried also 10'000 or 100'000 but with them sometimes an access violation is generated. Probably, using factor greater than 1 million can even better the situation, I do not know)
|
|
|
|
|
I have a databinding issue with a numericupdown control bound to a bindinglist of objects. The updown control is located on a usercontrol. The controls can be loaded with values from a file located in a defaults xml file. The databinding works as it should upon loading the defaults file the first time. If during the session, I want to reload the defaults the databinding is lost. I can see that the values are loaded in correctly, but the numericupdn doesn't change value. here's a simplified version of my code to help explain.
Object class:
public class Garage :
{
public BindingList<DrawerData> Drawer = new BindingList<DrawerData>
{
new DrawerData(),
new DrawerData()
};
}
public class DrawerData : INotifyPropertyChanged
{
private decimal _NumberOfTools;
public event PropertyChangedEventHandler PropertyChanged;
public decimal NumberOfTools
{
get { return _NumberOfTools; }
set {
if (_NumberOfTools != value)
{
_NumberOfTools = value;
OnPropertyChanged("NumberOfTools");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string PropertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
}
}
Usercontrol class:
public partial class UcDrawer : UserControl, INotifyPropertyChanged
{
private readonly Garage _Garage;
private readonly int Drw
BindingSource bindingSource = new BindingSource();
public event PropertyChangedEventHandler PropertyChanged;
public UcDrawer(int drw,Garage garage)
{
_Garage = garage;
Drw = drw;
bindingSource.DataSource = _Garage.Drawer[Drw];
}
private void UcDrawer_Load(object sender, EventArgs e)
{
UpDnSettingsNumberOfTools.DataBindings.Add(new Binding("Value", bindingSource, "NumberOfTools", true, DataSourceUpdateMode.OnPropertyChanged));
}
}
Form where usercontrol is used (it's loaded into tabpages in a tabcontrolon the form):
public partial class FrmGarage : Form
{
private readonly int Drw;
private readonly Garage _Garage;
public FrmGarage(int drw, Garage garage )
{
InitializeComponent();
Drw = drw;
_Garage = garage;
}
private void FrmGarage_Load(object sender, EventArgs e)
{
for (int i = 0; i < ch; i++)
{
AddTab(i + 1);
}
}
private void AddTab(int ChNum)
{
UcDrawer ucDrawer = new UcDrawer(Drw, _Garage) { Dock = DockStyle.Fill };
TabPage myTabPage = new TabPage();
myTabPage.Controls.Add(ucDrawer);
GarageTabControl.TabPages.Add(myTabPage);
myTabPage.Name = "Drawer" + Drw;
myTabPage.Text = "Drawer " + Drw;
}
}
}
Main form (has buttons on a side list that load different forms into a panel, i'll only include the garage one for simplicity)
public partial class Form1 : Form
{
public Garage garage;
readonly private FrmGarage FrmGarage_vrb;
private Form ActiveMainForm = null;
public Form1()
{
InitializeComponent();
garage = new Garage();
FrmGarage_vrb = new FrmGarage(2, garage) { Dock = DockStyle.Fill, TopLevel = false, TopMost = true };
}
private void MainButtonListClickAction(Button buttonClicked, Form formActivated)
{
pnlNav.Height = buttonClicked.Height;
pnlNav.Top = buttonClicked.Top;
this.pnlFormLoader.Controls.Clear();
this.pnlFormLoader.Controls.Add(formActivated);
formActivated.Show();
ActiveMainForm = formActivated;
}
public void BtnOverride_Click(object sender, EventArgs e)
{
MainButtonListClickAction(BtnGarage, FrmGarage);
}
private void BtnMainNew_Click(object sender, EventArgs e)
{
XmlSerializer serializer = new XmlSerializer(typeof(BindingList<DrawerData>));
XmlReader reader = XmlReader.Create("defaults.xml");
garage.Drawer = (BindingList<DrawerData>)serializer.Deserialize(reader);
reader.Close();
}
|
|
|
|
|
Didn't see anything in there that looked like a "numeric up/down control".
It was only in wine that he laid down no limit for himself, but he did not allow himself to be confused by it.
― Confucian Analects: Rules of Confucius about his food
|
|
|
|
|
It's in the UcDrawer class. The usercontrol layout was made in the design view. It is the UpDnSettingsNumberOfTools control located in this line:
UpDnSettingsNumberOfTools.DataBindings.Add(new Binding("Value", bindingSource, "NumberOfTools", true, DataSourceUpdateMode.OnPropertyChanged));
|
|
|
|
|
Just a guess, since Windows Forms seem to be morphing into WPF ... Changing / selecting tabs fires its own loaded and unloaded events (in WPF) and it looks like your UpDown is on a tab.
It was only in wine that he laid down no limit for himself, but he did not allow himself to be confused by it.
― Confucian Analects: Rules of Confucius about his food
|
|
|
|
|
@PIEBALDconsult, sorry for trouble, but the article is deleted and I lost your comment "Could be simplified a bit". Can you remind me the link (on stackoverflow.com) to your solution? Thanks.
|
|
|
|
|
Most likely I was pointing out that typeof(T).GetFields is better than System.Enum.GetNames
and that using ToString on an enem value is better than trying to do it yourself.
|
|
|
|
|
|
PIEBALDconsult wrote: typeof(T).GetFields is better than System.Enum.GetNames
Enum.GetNames calls typeof(T).GetEnumNames , which then calls typeof(T).GetFields , so there's not going to be a huge difference.
However, GetEnumNames sorts the names by the value of the enum member, so there may be a very small performance hit there.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Right. Sorting is unnecessary as we're just adding them to a Dictionary anyway and losing the order.
Not a huge difference performance, particularly as it should happen only once per run and an enum should have few members to begin with.
My earlier comment on an "article" also pointed out that the Dictionary (ies) can be static because they don't change.
I'll also add though, that my implementation also supports having a DescriptionAttribute on each member and that can only be retrieved by retrieving the members (fields), not simply enumerating the names.
Plus... I allow finding an enum value by an abbreviated name, not just the full name, but that's not often useful.
|
|
|
|
|
How C# handles binary files?
I already know how to read binary files with the "ReadAllText" command.
|
|
|
|
|
Member 14773258 wrote: I already know how to read binary files with the "ReadAllText" command. Then, unfortunately, you do not know how to read binary files. If you read a binary file as text then it is very likely that the data will be corrupted as the system tries to interpret characters such as return (\r ) and line feed (\n ). To read binary files correctly you must read them in raw mode into arrays of pure bytes. From there you need to know the structure of the data in the files before you can do anything useful with it.
|
|
|
|
|
You very definitely don't read binary file data with ReadAllText - you need ReadAllBytes[^] which returns a byte[] instead of a string.
Strings are made of characters, which are generally variable length: they could be 8 bit, they could be 16 - and reading binary data as text is a very good way to corrupt it beyond hope of recovery.
This may help: ByteArrayBuilder - A StringBuilder for Bytes[^] it allows you to apply some "structure" to a binary file and read it in a "sensible" way. If nothing else, it shows one way to handle binary data files, but if your data files already exist and you must read them, then you will probably need to take a good hard look at the file format before you get started - there will be a structure applied to it, but what structure depends on the developer who produced them!
If you are to produce your own dtaa files, then it's probably a better idea to look at using JSON or even XML instead of binary data - it's much, much easier to handle I/O as both can "fill classes" for you when your read or write the data. Saves a whole load of work!
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
"Common sense is so rare these days, it should be classified as a super power" - Random T-shirt
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
|
how to create this program??
a program that will ask the user to enter positive number and loop/ continue until the user input a negative value and stops the loop.
The program will display
● The total number of positive numbers input
● The maximum (Highest) value
● The minimum (Lowest) value
● The equation
● And the average
Note:
● When the input is ZERO, the program will display a message that tells the user must input a positive or negative value, and ask the user to enter again a value
● ZERO will be discarded
|
|
|
|
|
We are more than willing to help those that are stuck: but that doesn't mean that we are here to do it all for you! We can't do all the work, you are either getting paid for this, or it's part of your grades and it wouldn't be at all fair for us to do it all for you.
So we need you to do the work, and we will help you when you get stuck. That doesn't mean we will give you a step by step solution you can hand in!
Start by explaining where you are at the moment, and what the next step in the process is. Then tell us what you have tried to get that next step working, and what happened when you did.
If you are having problems getting started at all, then this may help: How to Write Code to Solve a Problem, A Beginner's Guide[^]
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
"Common sense is so rare these days, it should be classified as a super power" - Random T-shirt
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
|
First C# Program
It was only in wine that he laid down no limit for himself, but he did not allow himself to be confused by it.
― Confucian Analects: Rules of Confucius about his food
|
|
|
|
|