Autor Beitrag
Ivy
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 228



BeitragVerfasst: Mo 19.07.10 09:19 
Hallo zusammen,
ich habe die Aufgabe ein Programm zu erstellen, das einen eingeben Wert formatiert wieder ausgibt. Die Funktion soll dabei automatisch den Prefix der Einheit anpassen!
Also die Präfixe wären in diesem FAll: f, p, n, µ, m, k, M, G, T"
(siehe: de.wikipedia.org/wik...r_Ma%C3%9Feinheiten)

Parameter:
- Messwert als double
- Anzahl signifikanter Stellen (das ist nicht zwangsläufig die Anzahl der Nachkommastellen!)
- Einheit
- Ein optionales Flag, welches Kennzeichnet, ob die Prefixe "f, p, n, µ, m" verwendet werden dürfen.
(manchmal macht es keinen Sinn z.Bsp. aus 0.5 Hz 500 mHz zu machen)

Eine Beispiel ausgabe könnte so aussehen:

Messwert 2.51236 V
signifikanter Stellen 3
Ausgabe 2.51 V

Messwert 0.251236 V
signifikanter Stellen 3
Ausgabe 251 mV

Messwert 2512.36 V
signifikanter Stellen 3
Ausgabe 2510 kV

Messwert 2512.36 V
signifikanter Stellen 5
Ausgabe 2512.4 kV

Messwert 2512360 V
signifikanter Stellen 3
Ausgabe 2.51 MV


Ich hab keine Ahnung wie ich das machen soll, vielleicht kann mir jemand einen guten Denkanstoß geben =)

lg ivy


Moderiert von user profile iconChristian S.: Topic aus WinForms verschoben am Mo 19.07.2010 um 09:28
IsNull
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 97
Erhaltene Danke: 11


VS 2010, C#, AHK
BeitragVerfasst: Mo 19.07.10 10:26 
Hallo,

Als Grundansatz würde ich etwas in der Richtung vorschlagen:
ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
public enum VoltEntity{
    V,
    mV,
    KV
    //muss natürlich mit allen Einheiten ergenzt werden
}

public class Volt
{
    private double mValue; //intern halten wir die anzahl immer als Volt
    Dictionary<VoltEntity, float> DependencyTable; //Tabelle um die Umrechnungen zu verwalten

    public Volt() {
        SetUpDependencyTable();
    }


    public string GetValueInOptimal(bool AddPrefix = true) {
        // Das ist die HauptMethode, die den Volt-Eintrag optmal zurückliefert, also in der besten grösse
    }

    private VoltEntity FindBestVoltEntity(){
        //Sucht die beste Einheit
    }
     


    /// <summary>Gibt die Volt-Value in der gewünschten Einheit zurück
    /// 
    /// </summary>
    /// <param name="VoltFormat"></param>
    /// <returns></returns>
    public double GetVoltAs(VoltEntity entity) {

        if (DependencyTable.ContainsKey(entity)) {
            return mValue * DependencyTable[entity];
        } else {
            return 0;
        }
    }

    private void SetUpDependencyTable(){

        DependencyTable = new Dictionary<VoltEntity, float>();
        DependencyTable.Add(VoltEntity.KV, 1000f);    //KiloVolt, d.h. Volt * 1000 = KV
        DependencyTable.Add(VoltEntity.mV, 0.001f);    //mV MiliVolt, d.h. Volt * 0.001 = mV
        //Hier die restilchen Umrechnungen eintragen

    }

}



Der Ansatz ist, dass du in der Klasse Volt intern deine Voltanzahl immer in Volt speicherst. D.h. beim Instanzieren der Volt Klasse müsstest du etwaige Prefixe/Suffixe schon auswerten und dann auch anhand der DependencyTable in Volt umrechnen.

Dann kannst du zumindest mal die Umrechnungen mit der DependencyTable einfach und übersichtlich lösen. Die Problematik mit der Signifikanten Stellen wird vom Code noch nicht beachtet, aber das sollte dann noch eine kleinigkeit sein.

Schau dir den Code mal an und versuche ihn weiterzuentwickeln.

Für diesen Beitrag haben gedankt: Ivy
Ivy Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 228



BeitragVerfasst: Mo 19.07.10 11:05 
Hey,
super danke, das hat mich schonmal ein ganzes stück weiter gebracht. Habe deinen Code jetz erweitert, nur wie ich das mit den signifikanten stellen machen soll weiß ich noch nicht^^
und was muss ich in der Methode GetValueInOptimal und FindBestVoltEntity genau machen?
norman2306
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 222
Erhaltene Danke: 16

Win XP, Win 7 64-Bit
C# 4.0 (VS2010)
BeitragVerfasst: Mo 19.07.10 11:27 
Ich würde es in eine Funktion packen.

Du hast eine Funktion mit vier eingaben: die Realzahl zum Konvertieren und die Ganzzahl signifikanter Stellen. Dann noch die Einheit und ein bool, ob die Präfixe verwendet werden soll. Und diese Funktion gibt dir einen string zurück.

ausblenden C#-Quelltext
1:
2:
3:
private string ConvertToPhysikal(double value, int significance, string unit,bool usePrefix)
{
}


so, in der Funktion zählst du die Anzahl der Stellen, die deine Zahl hat. Da es mit dem zählen für den Rechner etwas kompliziert ist, bedienst du dich eines kleinen Tricks:

du nimmst den log10 der Zahl, denn

log 0,000001 = -6 := µ
log 0,001 = -3 := m
log 1000 = 3 := k

Die anderen Zahlen liegen immer dazwischen.
usw.

Das Ganze kannst du dann in eine Switch oder if schleife bauen:

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
string prefix = "";
double devisor = 1;
switch((int)(value != 0 ? Math.Log10(value)/3 : 0))
{
   case: -5
     prefix = "f";
     devisor = 10e-15;
   case: -4
     prefix = "p";
     devisor = 10e-12;
   .
   .
   .
   case3
     prefix = "G";
     devisor = 10e9;
   .
   .
   .
   default:
     prefix = "";
     devisor = 1;
}


obwohl ich glaube, das die Angabe der Signifikanz so wie du es machst wenig sinnvoll ist (normalerweise gibt die Signifikanz die Anzahl der Kommastellen) kann man das wieder mit dem logarithmus lösen. Mal qualitativ angegeben:

ausblenden C#-Quelltext
1:
2:
int rad = 10^((-Floor(log10(value))+significance - 1);
double rvalue = Math.Round(value * rad,0)/rad;


rvalue.ToString() liefert dir jetzt die korrekte Ausgabe (du könntest es auch über Format machen, aber ich denke, dass wäre komplizierter.

Also jetzt noch zusammenbauen mit einem StringBuilder, den Devisor nicht vergessen und das war´s dann auch schon.


Zuletzt bearbeitet von norman2306 am Mo 19.07.10 16:08, insgesamt 1-mal bearbeitet
Ivy Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 228



BeitragVerfasst: Mo 19.07.10 15:27 
aha, ja klingt logisch. Aber, wie was mit dem String Builder machen? versteh ich nicht so ganz^^
und warum setzte ich den devisor = 1? braucht man doch nicht oder?
norman2306
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 222
Erhaltene Danke: 16

Win XP, Win 7 64-Bit
C# 4.0 (VS2010)
BeitragVerfasst: Mo 19.07.10 16:02 
Eigentlich solltest du dir ja auch selber ein paar Gedanken machen und wenn du nicht weiter kommst, fragen. So steht´s in den Forumsregeln.

Den Devisor brauchst du, um ihn mit deinem Value zu multiplizieren... der gibt die Kommaverschiebung an, wenn du einen Präfix davorsetzt. So zu sagen der Dezimalshift. Wenn du als Präfix "k" hast, musst du dein value ja durch tausend rechnen, weil k = 1000.

also 1000 = 1 kHz, also devisor = 1000 = 10^3.
Ivy Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 228



BeitragVerfasst: Mo 19.07.10 16:10 
wer sagt dass ich mir keine gedanken gemacht habe? Vielleicht habe ich mich einfach nachdem ich mir gedanken gemacht habe und google befragt habe dazu entschlossen, hier noch einmal nachzufragen. weil wie du siehst ist zwischen deiner antwort un meinem post jede menge zeit vergangen...aber gut^^
norman2306
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 222
Erhaltene Danke: 16

Win XP, Win 7 64-Bit
C# 4.0 (VS2010)
BeitragVerfasst: Mo 19.07.10 16:19 
poste deinen bisherigen Code. Das ist immer der schlagfertigste Beweis:) Dann weiß ich a) dass du was gemacht hast und b) wo genau dein Problem liegt. Code sagt mehr, als tausend Worte.
Ivy Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 228



BeitragVerfasst: Di 20.07.10 08:07 
okay, also bisher hab ich deine funktion für die signifikanten stellen so:

ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
  private string ConvertToPhysikal(double value, int significance, string unit, bool usePrefix) //Funktion Signifkikante Stellen berechnen
    {
        string prefix = "";
        double devisor = 1;
        switch((int)(value != 0 ? Math.Log10(value)/3 : 0))
{
            case -5:
     prefix = "f";
     devisor = 10e-15;
     break;
            case -4:
     prefix = "p";
     devisor = 10e-12;
     break;
            case -3:
     prefix = "n";
     devisor = 10e-9;
     break;
            case -2:
     prefix = "µ";
     devisor = 10e-6;
     break;
            case -1:
     prefix = "m";
     devisor = 10e-3;
     break;
            case 1:
     prefix = "k";
     devisor = 10e-3;            
            case 3:
     prefix = "G";
     devisor = 10e-9;
     break;
            case 4:
     prefix = "T";
     devisor = 10e-12;
     break;
            default:
     prefix = "";
     devisor = 1;
     break;
}
StringBuilder MyStringBuilder = new StringBuilder();
MyStringBuilder.AppendFormat(prefix, devisor);
return string.Format(prefix + "{0}");
Christoph1972
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 690
Erhaltene Danke: 16


VS2015 Pro / C# & VB.Net
BeitragVerfasst: Di 20.07.10 09:14 
Moin,

ich dachte hier werden keine Hausaufgaben erledigt :lol:

_________________
Gruß
Christoph
Ivy Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 228



BeitragVerfasst: Di 20.07.10 09:18 
user profile iconChristoph1972 hat folgendes geschrieben Zum zitierten Posting springen:
Moin,

ich dachte hier werden keine Hausaufgaben erledigt :lol:


sind kine hausaufgaben, ist ein projekt was ich in der arbeit erledigen muss :-/ wenn mand as nicht darf, wozu ist das forum dann?
norman2306
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 222
Erhaltene Danke: 16

Win XP, Win 7 64-Bit
C# 4.0 (VS2010)
BeitragVerfasst: Di 20.07.10 09:19 
Naja... du weißt nicht so richtig, was du da machst^^


das return macht keinen Sinn. Das hatte ich in meinem ersten Post nur versehentlich drin.

Also gehen wir mal durch, was das der Code jetzt macht. Legen wir uns mal ein paar Werte vor:

ausblenden C#-Quelltext
1:
2:
3:
4:
value = 123456.78
significance = 4
unit = "m"
usePrefix = true


Nach kurzem überlegen sollte da also rauskommen: 123.5 km

das erste was jetzt gemacht wird, ist die switch-Anweisung... also es wird Math.Log10(value)/3 berechnet

ausblenden C#-Quelltext
1:
Math.Log10(123456.78)/3 = 1.6971					


durch die (int)-Umwandlung wird das ganze automatisch abgerundet, also ist das Ergebnis 1. Er geht jetzt also zum Ergebnis 1 (case 1). Bei Case 1 wird das prefix auf "k" (Kilo) und der devisor auf 10e-3 = 10^-3 = 0.001... mmh, sieht mir schonmal nach einem Fehler aus... sollte das nicht 1000, also 10e3 sein? k= 1000? Naja, das findest du schon raus. Also, gehen wir mal von einem devisor=1000 aus.

Das break gibt an, dass der Bereich der switch-Anweisung verlassen werden soll. Also, wir haben jetzt:

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
value = 123456.78
significance = 4
unit = "m"
usePrefix = true
prefix = "k"
devisor = 1000


jetzt sollten wir uns ja eigentlich um die signifikanten Stellen kümmern... dafür hatte ich dir ja schonmal Code gesponsert...

ausblenden C#-Quelltext
1:
2:
int rad = 10^((-Math.Floor(Math.Log10(value))+significance - 1);
double rvalue = Math.Round(value * rad,0)/rad;


Das ergibt in unserem Beispiel:

ausblenden C#-Quelltext
1:
2:
int rad = 10^((-Math.Floor(Math.Log10(123456.78))+ 4 - 1) = 10e-2 = 0.01
double rvalue = Math.Round(value * 0.01,0)/0.01 = 123500


Fassen wir zusammen, was wir jetzt haben:

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
value = 123456.78
significance = 4
usePrefix = true

rvalue = 123500.0;
devisor = 1000
prefix = "k"
unit = "m"


Das sieht ja schon recht brauchbar aus... jetzt fragen wir uns mal, was wir haben wollten:
123.5 km. Die Frage ist nun, wie wir das aus den Sachen da oben bekommen. Ich meine, wie machen wir z.B. mit Hilfe des devisors = 1000 aus dem rvalue = 123500 unser nominales Ergebnis von 123.5????

Und wie setzen wir mit Hilfe des StringBuilders das dann zu einem brauchbaren ("123.5 km") Text zusammen

Und zu guter letzt gilt es ja dann auch noch usePrefix auszuwerten... Aber ich denke, dass sind lösbare Aufgaben.
norman2306
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 222
Erhaltene Danke: 16

Win XP, Win 7 64-Bit
C# 4.0 (VS2010)
BeitragVerfasst: Di 20.07.10 09:27 
Zitat:
wenn mand as nicht darf, wozu ist das forum dann?


In diesem Forum wird geholfen, wenn jemand an einem Punkt nicht weiter kommt. Normalerweise wir nur auf explizite Fragen geantwortet. Besonders wenn es sich um recht einfache Dinge handelt. Fertiger Code wird nur in Ausnahmefällen geliefert (bei meist komplexen Sachen oder Optimierungsaufgaben)...
Ivy Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 228



BeitragVerfasst: Di 20.07.10 10:01 
ja sorry, tut mir ja leid dass ich ein wenig zu doof bin -.-

zu diesem code schnipsel:

ausblenden C#-Quelltext
1:
2:
int rad = 10^((-Math.Floor(Math.Log10(value))+significance - 1);
double rvalue = Math.Round(value * rad,0)/rad;


ich hatte ihn wieder herausgenommen da ein fehler kam; "Der Operator "^" kann nicht auf Operanden vom Typ "int" und "double" angewendet werden"

ansonsten ist es mir jetz schon klarer geworden, dank deiner schritt für schritt (für doofe) erklärung

beim Case1 habe ich jetz statt -3, +3 (10e3 = 10^3 = 1000)

Zitat:
Ich meine, wie machen wir z.B. mit Hilfe des devisors = 1000 aus dem rvalue = 123500 unser nominales Ergebnis von 123.5????


123500/1000=123,5 oder?
norman2306
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 222
Erhaltene Danke: 16

Win XP, Win 7 64-Bit
C# 4.0 (VS2010)
BeitragVerfasst: Di 20.07.10 10:20 
jop, "^" ist auch nicht korrekt, dass ist aus EXCEL. Mein Code enthält schon aus Prinzip Fehler. Du musst

ausblenden C#-Quelltext
1:
Math.Pow(10, -Math.Floor(Math.Log10(value)+significance - 1)					


stattdessen schreiben.

Du musst das auch bei allen anderen "Case > 0" ändern.
Ivy Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 228



BeitragVerfasst: Di 20.07.10 11:01 
okay, bin jetz mal so weit:

ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
     private string ConvertToPhysikal(double value, int significance, string unit, bool usePrefix)
            {
                string prefix = "";
                double devisor = 1;
                switch ((int)(value != 0 ? Math.Log10(value) / 3 : 0))
                {
                    case 1:
                        prefix = "k";
                        devisor = 10e3;
                        break;
                    case 2:
                        prefix = "M";
                        devisor = 10e6;
                        break;
                    case 3:
                        prefix = "G";
                        devisor = 10e9;
                        break;
                    case 4:
                        prefix = "T";
                        devisor = 10e12;
                        break;
                    case -5:
                        prefix = "f";
                        devisor = 10e-15;
                        break;
                    case -4:
                        prefix = "p";
                        devisor = 10e-12;
                        break;
                    case -3:
                        prefix = "n";
                        devisor = 10e-9;
                        break;
                    case -2:
                        prefix = "µ";
                        devisor = 10e-6;
                        break;
                    case -1:
                        prefix = "m";
                        devisor = 10e-3;
                        break;
                                    
                    default:
                        prefix = "";
                        devisor = 1;
                        break;
                }
                double rad =  Math.Pow(10, -Math.Floor(Math.Log10(value) + significance - 1));
                double rvalue = Math.Round(value * rad, 0) / rad;

                System.Text.StringBuilder sb = new System.Text.StringBuilder();
                sb.Append(rvalue/devisor); //123500/1000=123,5
                sb.Append(prefix); //k
                sb.Append("Volt"); //Volt
                return sb.ToString();  //---->123,5kVolt



Was genau muss ich noch mit dem useprefix machen?
norman2306
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 222
Erhaltene Danke: 16

Win XP, Win 7 64-Bit
C# 4.0 (VS2010)
BeitragVerfasst: Di 20.07.10 14:47 
Das usePrefix hast du in deiner Aufgabenstellung bereits gesagt....

du machst ja:
ausblenden C#-Quelltext
1:
2:
3:
4:
                sb.Append(rvalue/devisor); //123500/1000=123,5
                sb.Append(prefix); //k
                sb.Append("Volt"); //Volt
                return sb.ToString();  //---->123,5kVolt


aber was ist zum Beispiel bei Hz?

also machst du ein Konstrukt wie

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
if(!usePrefix && devisor < 1)
{
  //Ergebnis ohne Prefix
}
else
{
  //Ergebnis mit Prefix
}


Außerdem würde ich den Text "Volt" noch durch <unit> ersetzen, die du ja der Funktion übergibst. Mal davon abgesehen ist es unüblich, kVolt anzugeben. Das entspricht nicht den SI-Richtlinien. Entweder kV oder Kilovolt.
Ivy Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 228



BeitragVerfasst: Di 27.07.10 08:52 
Hey,
ich habe jetzt nochmal nachgerechnet, wie kommst du eigentlich drauf
Math.Log10(123456.78)/3 = 1.6971 ergbit?
wenn ich 123456.78/3 rechne bekomme ich 41152.26 heraus?!

und bei diesem:
ausblenden C#-Quelltext
1:
int rad = 10^((-Math.Floor(Math.Log10(123456.78))+ 4 - 1) = 10e-2 = 0.01					


wie kommst du da auf 10^-2?
danielf
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 1012
Erhaltene Danke: 24

Windows XP
C#, Visual Studio
BeitragVerfasst: Di 27.07.10 08:57 
Das nennt sich Mathematik.

Er rechnet nicht 123456,78 / 3 sondern den Logarithmus von 123456,78 und das Resultat durch 3..

10^-2 ist eine andere Schreibweise für 0.1 ...

Findest du bestimmt auch alles in deine Mathebücher oder bei google.
Ivy Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 228



BeitragVerfasst: Di 27.07.10 09:08 
ahja...noch nie von logarthismus gehört^^

ich hab noch ein problem, rvalue setzt mein programm immer auf 0, also rechnet nicht das
ausblenden C#-Quelltext
1:
 double rvalue = Math.Round(value * ergebnis, 0) / ergebnis;					

hat jemand ne ahnung warum? bin noch am verzweifeln -.-

edit: habs gelöst durch die 0 hatte mein rvalaue keine dezimalstellen


Zuletzt bearbeitet von Ivy am Di 27.07.10 09:30, insgesamt 3-mal bearbeitet