Permalänk
Medlem

c# amerikanen i bastun

Hej!

Behöver hjälp med en uppgift i Programmering 1 som lyder:

Denna uppgift går ut på att en amerikanare ska skriva in en temperatur för ett bastuaggregat tills man skriver in
en temperatur som anses lagom. För att kontrollera detta ska vi ha en temperatur som anger den lägsta
godtagbara temperaturen och en som anger den högsta godtagbara temperaturen.
Tyvärr förstår vår kära bastubesökare enbart Fahrenheit medan
bastuaggregatet enbart förstår Celsius. Därför har du fått skriva ett program
som konverterar det som skrivs in från Fahrenheit till Celsius.
Den optimala temperaturen för bastun är 75 grader men den godtagbara
temperaturen är från 73 till 77 grader. Detta ska styras hela i villkorssatsen i
loopen.
Om talet är mindre än den minsta godtagbara temperaturen ska programmet
skriva att det är för kallt och man får skruva upp lite. Därefter får
bastubesökaren ställa in ett nytt värde på bastuaggregatet och loopen
upprepas.
I denna uppgift ska ni hantera följande:
1. Undantagshantering
2. Metoder
3. Villkor
Då amerikanaren kan skriva in i Fahrenheit så innebär det ett värde på 167 grader (=75 grader) men det vet ju
inte han eller hon då det är deras första bastubesök någonsin.
Läshänvisningar
Film 1,2 och 3 i min spellista på Youtube
Lämpliga sidor i läroboken
Csharpskolan och följande artiklar:
• Funktioner och metoder
• Felhantering och undantag
Vad sa älgen som bastade?
Planering
Ni ska skapa aktivitetsdiagram för denna uppgift. Då finns några saker att påpeka.
Undantagshantering behöver inte finns med i aktivitetsdiagrammet. Det är inget som behövs för att visualisera
flödet av kod.
Man gör ett aktivitetsdiagram per metod, eller varje metod ska tydligt
separeras i figuren. För att visualisera ett anrop finns olika lösning. En sådan
är en särskild figur med två linjer på sidorna.
Sedan när programmen blir större och flera metoder är involverade, så får man komma på en lämplig lösning för
att visualisera alla metoder och hur dessa är sammankopplade.
Betyg E
Be användaren skriva in en temperatur i Fahrenheit
Detta värde ska skickas till en metod som gör om
Fahrenheit till Celsius:
Kodhjälp i koden till höger.
Denna metod heter FahrToCels och returnerar ett heltal.
Metoden tar emot ett värde som användaren skrivit in.
Därefter ska du komplettera med koden som krävs för att
användaren ska få skriva in en ny temperatur i Fahrenheit
om det är för kallt eller för varmt. Det innebär att du ska
lösa det med loopar och villkor på ett lämpligt sätt.
Här kommer en förklaring till pilarna:
1. Vi skapar en heltalsvariabel (celsius) som vi ska
tilldela ett värde.
2. Vi anropar en metod FahrToCels där vi skickar med värdet fahrenheit (exempelvis 140) som metoden
behöver för att fungera.
3. Detta värde (140) sparas som fahr i metoden och används för uträkningen av värdet cel som returneras
och lagras i variabeln celcius.
Betyg C
Omvandla fahrenheit till
celcius
1 2
3
Omräkningen från Fahrenheit till Celsius ovan är inte
optimal då det uträknade värdet för Celsius troligtvis blir
ett decimaltal och detta ”kapas” rakt av då detta värde
ovan lagras som heltal (int). Det avrundas alltså inte.
Lös uppgiften och att värdet Celsius sparas som ett flyttal
med decimaler.
För att en beräkning ska fungera med decimaltal måste
alla tal i formeln vara av flyttalstyp.
Denna formel kommer inte att fungera då fahr är ett
heltal.
double temp = (fahr - 32) * 5
/ 9;
Här behöver man alltså omvandla fahr till samma double (eller float om ni jobbar med det). Ett sätt att göra detta
på är att ”typomvandla” fahr i formeln ovan så det behandlas som en double i formeln.
För att lösa detta kan man jobba med så kallad explicit typomvandling som beskrivs på MSDNs hemsida med ett
enkelt exempel på följande länk:
https://msdn.microsoft.com/en-us/library/ms173105.aspx#Anchor...
Jag vill fortfarande att det tal användaren skriver in lagras i en int först eftersom man med stor sannolikhet bara
skriver in heltal. Det innebär att metoden ska se ut så här:
public static double FahrToCels(int fahr)
{
//Typomvandla fahr till flyttal
//Gör uträkning med decimaler i svaret
return temp;
}
Utöver detta fungerar programmet på ett liknande sätt förutom att det är ett decimaltal som testas mot en
lämplig temperatur.
Se om du också kan lösa det med att avrunda talet om du väljer att skriva ut det.
Programmet ska också kunna hantera fel som uppstår med try & catch.
Ett vanligt fel man gör när man jobbar med try och catch är att man lägger för mycket kod i try-blocket. Egentligen
ska bara själva typ-omvandlingen ligga här. Se exemplet på sidan 87 i läroboken eller se filmen om
undantagshantering.

Min kod:

class Program { public static double FahrToCels(int fahr) { double temp; temp = (double)fahr; temp = (temp - 32) * 5 / 9; return temp; } static void Main(string[] args) { int fahrenheit; double celsius = 0; Console.WriteLine("Skriv in fahrenheit: "); do { try { fahrenheit = Convert.ToInt32(Console.ReadLine()); celsius = FahrToCels(fahrenheit); } catch (Exception) { Console.WriteLine("Skriv in ett heltal: "); } if (celsius > 77) { Console.WriteLine("Sänk temperaturen!"); } else if (celsius < 73) { Console.WriteLine("Höj temperaturen!"); } else if (celsius == 75) { Console.WriteLine("Nu är det perfekt, temperaturen är {0} grader celsius", celsius); } } while (celsius <= 73 || celsius >= 77); Console.WriteLine("Nu är temperaturen {0} grader celsius, perfekt för att basta!", celsius); Console.ReadKey(); } }

Mitt problem är att när jag skriver in en bokstav istället för siffra så kommer det (som det ska) "skriv in ett heltal: " MEN det kommer även "höj temperaturen!". Jag fattar inte vad som är fel.. Har bara gjort loopar en gång innan och då gjorde det inte såhär. Säkert något enkelt som jag inte fattar :'). Kan någon snälla hjälpa mig?
Tack!

Permalänk
Medlem

Vad händer när datorn tuggat igenom catch-blocket och fortsätter exekveringen? (Menat som en ledtråd...)

Permalänk
Medlem

Spontant utan att läsa hela anvisningarna, flytta in dina if satser innanför try. Så som det står nu så körs if-satserna oavsett om användaren anger ett tal eller en bokstav.

Om användaren angett en bokstav så är celsius = 0 och därmed är if (celsius < 73) sann.

Visa signatur

Citera, så svarar jag också gärna :)

Permalänk
Medlem

Jag fyller på med lite mer ledtråd. Längre upp i koden så använder du

Console.WriteLine("Skriv in fahrenheit: ");

För att uppmana användaren till att mata in något.

Utan try/catch så tar du hand om inmatningen på följande vis:

fahrenheit = Convert.ToInt32(Console.ReadLine()); celsius = FahrToCels(fahrenheit);

Du hamnar ju i catch-delen när något fel har inträffat och då ber du användaren om en mer korrekt input

Console.WriteLine("Skriv in ett heltal: ");

Men du saknar kod för att ta omhand om ny input?

Det värde som celsius har i detta läget har aldrig ändrats från dess startvärde som är 0.

Permalänk
Medlem
Skrivet av Lambda²:

Spontant utan att läsa hela anvisningarna, flytta in dina if satser innanför try. Så som det står nu så körs if-satserna oavsett om användaren anger ett tal eller en bokstav.

Om användaren angett en bokstav så är celsius = 0 och därmed är if (celsius < 73) sann.

Det funkade perfekt!
Men det enda är att enligt läroböckerna och videolektionerna så sägs det "Ett vanligt fel man gör när man jobbar med try och catch är att man lägger för mycket kod i try-blocket. Egentligen ska bara själva typ-omvandlingen ligga här. Se exemplet på sidan 87 i läroboken eller se filmen om undantagshantering."
Jag tolkade det som att man bara fick/skulle använda: "fahrenheit = Convert.ToInt32(Console.ReadLine());" och "celsius = FahrToCels(fahrenheit);" i Try för att där inte skulle vara för mycket text.

Men nu funkar det som jag vill så det får vara så!
Tack så jätte mycket för hjälpen!

Permalänk
Medlem

Tänk på att om du inte säger något annat så kommer koden köras uppifrån och ner.
Alltså i ordning
Try
catch
if
else if
else if

om du kollar på var du skriver ut "höj temperaturen" och debuggar koden neråt och kollar på värdet av celsius så borde du förstå vad som händer och varför.
Du behöver se till att du inte uppfyller eller kommer till den if:en om du skriver ut höj temperaturen

Visa signatur

Fractal Design Node 304 -> ASUS ROG STRIX Z370-I GAMING ->i5 8600K -> be quiet! Pure Rock -> MSI GeForce RTX 4070 VENTUS 2X E 12G OC -> Corsair Vengeance LPX 3200 32GB -> Seasonic FOCUS Plus 650W Gold -> Samsung 960 EVO 500GB -> 2 * Western Digital Black 2 TB -> Samsung 850 EVO Basic SSD 500GB

Permalänk
Medlem
Skrivet av Almarea:

Det funkade perfekt!
Men det enda är att enligt läroböckerna och videolektionerna så sägs det "Ett vanligt fel man gör när man jobbar med try och catch är att man lägger för mycket kod i try-blocket. Egentligen ska bara själva typ-omvandlingen ligga här. Se exemplet på sidan 87 i läroboken eller se filmen om undantagshantering."
Jag tolkade det som att man bara fick/skulle använda: "fahrenheit = Convert.ToInt32(Console.ReadLine());" och "celsius = FahrToCels(fahrenheit);" i Try för att där inte skulle vara för mycket text.

Men nu funkar det som jag vill så det får vara så!
Tack så jätte mycket för hjälpen!

Inga problem, lärobocken har helt rätt man bör hellst ha så lite kod som möjligt i try/catch blocken. Försök tänka dig en lösning som flyttar ut if satserna från try igen.

Visa signatur

Citera, så svarar jag också gärna :)

Permalänk
Medlem
Skrivet av Verdurakh:

Tänk på att om du inte säger något annat så kommer koden köras uppifrån och ner.
Alltså i ordning
Try
catch
if
else if
else if

om du kollar på var du skriver ut "höj temperaturen" och debuggar koden neråt och kollar på värdet av celsius så borde du förstå vad som händer och varför.
Du behöver se till att du inte uppfyller eller kommer till den if:en om du skriver ut höj temperaturen

Jag förstår varför den skriver ut det nu, "celsius = 0" och "är celsius mindre än 73, skriv ut höj temperaturen" men min celsius blir rödmarkerad om jag tar bort celsius = 0; . Hur ska man skriva det för att det inte ska bli rödmarkerat?

Permalänk
Medlem

Ett "continue" i catch-blocket borde funka också utan att du flyttar in nån kod i try-blocket.

Skrivet av Almarea:

Det funkade perfekt!
Men det enda är att enligt läroböckerna och videolektionerna så sägs det "Ett vanligt fel man gör när man jobbar med try och catch är att man lägger för mycket kod i try-blocket. Egentligen ska bara själva typ-omvandlingen ligga här. Se exemplet på sidan 87 i läroboken eller se filmen om undantagshantering."
Jag tolkade det som att man bara fick/skulle använda: "fahrenheit = Convert.ToInt32(Console.ReadLine());" och "celsius = FahrToCels(fahrenheit);" i Try för att där inte skulle vara för mycket text.

Men nu funkar det som jag vill så det får vara så!
Tack så jätte mycket för hjälpen!

Permalänk
Medlem
Skrivet av tsv:

Ett "continue" i catch-blocket borde funka också utan att du flyttar in nån kod i try-blocket.

Det funkade också. Perfekt, tack så mycket för hjälpen!

Permalänk
Medlem
Skrivet av Almarea:

Jag förstår varför den skriver ut det nu, "celsius = 0" och "är celsius mindre än 73, skriv ut höj temperaturen" men min celsius blir rödmarkerad om jag tar bort celsius = 0; . Hur ska man skriva det för att det inte ska bli rödmarkerat?

Du måste ju fortfarande ha variabeln och typen int måste ha en siffra så du måste hitta en annan lösning.

Som dom andra svarat och du redan testat så finns continue.

Men hoppas du förstår varför continue fungerar också?
Om inte så läs på lite om loopar och kolla vad break och continue gör

Visa signatur

Fractal Design Node 304 -> ASUS ROG STRIX Z370-I GAMING ->i5 8600K -> be quiet! Pure Rock -> MSI GeForce RTX 4070 VENTUS 2X E 12G OC -> Corsair Vengeance LPX 3200 32GB -> Seasonic FOCUS Plus 650W Gold -> Samsung 960 EVO 500GB -> 2 * Western Digital Black 2 TB -> Samsung 850 EVO Basic SSD 500GB

Permalänk
Medlem
Skrivet av Almarea:

Det funkade också. Perfekt, tack så mycket för hjälpen!

Ett annat lite mer generellt alternativ till continue kan vara att flytta en rimlig mängd kod till en ny metod som t.ex. returnerar true/false beroende på om ett godkänt värde lästs och skrivits till variablen. Det kräver dock att värdet är deklarerat i klassen i sig snarare än i main/nya metoden, så både metoden kan skriva det om det lästes ok, samt main kan läsa det.

Kanske inte värt att göra för detta när continue passar, men kan vara värt att tänka på i andra fall.

Visa signatur

Redbox: Asrock B650 Lightning ATX, 7800x3D -20CCO, XFX 6950XT, 2x32GB Corsair Vengence 6400 CL32, WD SN770 2TB, Corsair RMe 1000, Lian Li Lancool 216, Peerless Assassin 120 SE
Purpbox: Z87-Pro, I5 4670K@4.2, Sapphire 290 TRI-X, 2x8GB Crucial Tactical@stock, Deep Silence 1
Samsung Evo 250+500GB + QVO 1TB, 2x1TB 7200RPM backup/lagring
Det var bättre förr: E5300 2600MHz -> 3640MHz, Celeron 300A -> 450MHz