| Autor |
Beitrag |
Ivy
      
Beiträge: 228
|
Verfasst: 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 Christian S.: Topic aus WinForms verschoben am Mo 19.07.2010 um 09:28
|
|
IsNull
      
Beiträge: 97
Erhaltene Danke: 11
VS 2010, C#, AHK
|
Verfasst: Mo 19.07.10 10:26
Hallo,
Als Grundansatz würde ich etwas in der Richtung vorschlagen:
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 }
public class Volt { private double mValue; Dictionary<VoltEntity, float> DependencyTable; public Volt() { SetUpDependencyTable(); }
public string GetValueInOptimal(bool AddPrefix = true) { }
private VoltEntity FindBestVoltEntity(){ }
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); DependencyTable.Add(VoltEntity.mV, 0.001f); }
} |
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 
      
Beiträge: 228
|
Verfasst: 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
      
Beiträge: 222
Erhaltene Danke: 16
Win XP, Win 7 64-Bit
C# 4.0 (VS2010)
|
Verfasst: 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.
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:
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; . . . case: 3 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:
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 
      
Beiträge: 228
|
Verfasst: 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
      
Beiträge: 222
Erhaltene Danke: 16
Win XP, Win 7 64-Bit
C# 4.0 (VS2010)
|
Verfasst: 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 
      
Beiträge: 228
|
Verfasst: 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
      
Beiträge: 222
Erhaltene Danke: 16
Win XP, Win 7 64-Bit
C# 4.0 (VS2010)
|
Verfasst: 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 
      
Beiträge: 228
|
Verfasst: Di 20.07.10 08:07
okay, also bisher hab ich deine funktion für die signifikanten stellen so:
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) { 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
      
Beiträge: 690
Erhaltene Danke: 16
VS2015 Pro / C# & VB.Net
|
Verfasst: Di 20.07.10 09:14
Moin,
ich dachte hier werden keine Hausaufgaben erledigt 
_________________ Gruß
Christoph
|
|
Ivy 
      
Beiträge: 228
|
Verfasst: Di 20.07.10 09:18
|
|
norman2306
      
Beiträge: 222
Erhaltene Danke: 16
Win XP, Win 7 64-Bit
C# 4.0 (VS2010)
|
Verfasst: 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:
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
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:
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...
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:
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:
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
      
Beiträge: 222
Erhaltene Danke: 16
Win XP, Win 7 64-Bit
C# 4.0 (VS2010)
|
Verfasst: 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 
      
Beiträge: 228
|
Verfasst: Di 20.07.10 10:01
ja sorry, tut mir ja leid dass ich ein wenig zu doof bin -.-
zu diesem code schnipsel:
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
      
Beiträge: 222
Erhaltene Danke: 16
Win XP, Win 7 64-Bit
C# 4.0 (VS2010)
|
Verfasst: 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
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 
      
Beiträge: 228
|
Verfasst: Di 20.07.10 11:01
okay, bin jetz mal so weit:
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); sb.Append(prefix); sb.Append("Volt"); return sb.ToString(); |
Was genau muss ich noch mit dem useprefix machen?
|
|
norman2306
      
Beiträge: 222
Erhaltene Danke: 16
Win XP, Win 7 64-Bit
C# 4.0 (VS2010)
|
Verfasst: Di 20.07.10 14:47
Das usePrefix hast du in deiner Aufgabenstellung bereits gesagt....
du machst ja:
C#-Quelltext 1: 2: 3: 4:
| sb.Append(rvalue/devisor); sb.Append(prefix); sb.Append("Volt"); return sb.ToString(); |
aber was ist zum Beispiel bei Hz?
also machst du ein Konstrukt wie
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8:
| if(!usePrefix && devisor < 1) { } else { } |
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 
      
Beiträge: 228
|
Verfasst: 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:
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
      
Beiträge: 1012
Erhaltene Danke: 24
Windows XP
C#, Visual Studio
|
Verfasst: 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 
      
Beiträge: 228
|
Verfasst: 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
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
|
|
|