PDA

View Full Version : آموزش: محاسبات اعداد در ویژوال بیسیک



ROSTAM2
جمعه 29 مهر 1401, 19:13 عصر
سلام ب همه.

تابع Pow مقدار توان عدد ورودی اول را بر اساس ورودی دوم بر می گرداند:


Dim xNumn, yNum As Double
Console.Write("{0}", vbTab)
Select Case Words.Length
Case = 3
xNumn = Val(Words(1))
yNum = Val(Words(2))
Console.WriteLine("Computing: {0} ^ {1} ► {2}", xNumn, yNum, Pow(xNumn, yNum))
Case Else
Console.WriteLine("{2}{0}{1}{3}", vbNewLine, vbTab, "Computing Error!", "Need 2 Numbers for Computing.")
End Select


همچنین این محاسبه را می توان با کاراکتر ^ هم بدست آورد:

Console.WriteLine("Computing: {0} ^ {1} ► {2}", xNumn, yNum, xNumn ^ yNum)


154099

در این برنامه که یک Console Application هست با استفاده از کلمه دستوری Power یا حرف P و نوشتن دو عدد با فاصله از هم، براساس عدد دوم، توان عدد اول بدست می آید.


Imports System.Math
Module Module1


Sub Main()
Dim Words() As String = {""}
Do Until Words(0).ToLower = "quit"
Console.Write("Math:>")
Words = Console.ReadLine.Split(Space(1))
Select Case Words(0).ToLower
Case "p", "power"
Dim xNumn, yNum As Double
Console.Write("{0}", vbTab)
Select Case Words.Length
Case = 3
xNumn = Val(Words(1))
yNum = Val(Words(2))
Console.WriteLine("Computing: {0} ^ {1} ► {2}", xNumn, yNum, Pow(xNumn, yNum))
Console.Write("{0}", vbTab)
Console.WriteLine("Computing: {0} ^ {1} ► {2}", xNumn, yNum, xNumn ^ yNum)
Case Else
Console.WriteLine("{2}{0}{1}{3}", vbNewLine, vbTab, "Computing Error!", "Need 2 Numbers for Computing.")
End Select
End Select
Loop
End Sub


End Module


دانلود سورس:
154100

ROSTAM2
جمعه 29 مهر 1401, 20:33 عصر
بدست آوردن بزرگترین عدد از بین اعداد به کمک تابع Max

برای اینکار چون برنامه Console Application هست از تبدیل رشته به عدد توسط تابع Val استفاده شده است.

ازونجایی که تابع Max فقط می تونه بین دو عدد محاسبه کنه این تابع ایجاد شده بین اعداد موجود در آرایه بزرگترین عدد رو بر می گردونه.

Function Maximum(ParamArray Numbers() As String) As Double
Dim Expr As Double = Max(Val(Numbers(0)), Val(Numbers(1)))
For i = 2 To Numbers.Length - 1
Expr = Max(Expr, Val(Numbers(i)))
Next
Return Expr
End Function


دستور اصلی: Case "max" به Select Case از دستور پست اول اضافه می شه و با استفاده از کلمه ذستوری Max و نوشتن اعداد با فاصله از هم همه اعداد بصورت رشته در یک آرایه قرار می گیرد و به تابع Maximum ارائه می شود تا بیشترین عدد را برای چاپ برگرداند.

Case "max"
Dim Arr() As String = {}
Console.Write("{0}", vbTab)
Select Case Words.Length
Case >= 3
ReDim Arr(Words.Length - 2)
Array.ConstrainedCopy(Words, 1, Arr, 0, Words.Length - 1)
Console.WriteLine("Computing: Maximum Number ► {0}", Maximum(Arr))
Case Else
Console.WriteLine("{2}{0}{1}{3}", vbNewLine, vbTab, "Computing Error!", "Need 2 Numbers or More for Computing.")
End Select

154104
سورس برنامه:

ROSTAM2
جمعه 29 مهر 1401, 20:57 عصر
این هم تابع Minimum برای برگرداندن کوچکترین عدد بین اعداد:


Function Minimum(ParamArray Numbers() As String) As Double
Dim Expr As Double = Min(Val(Numbers(0)), Val(Numbers(1)))
For i = 2 To Numbers.Length - 1
Expr = Min(Expr, Val(Numbers(i)))
Next
Return Expr
End Function


کد اصلی:

Case "min"
Dim Arr() As String = {}
Console.Write("{0}", vbTab)
Select Case Words.Length
Case >= 3
ReDim Arr(Words.Length - 2)
Array.ConstrainedCopy(Words, 1, Arr, 0, Words.Length - 1)
Console.WriteLine("Computing: Minimum Number ► {0}", Minimum(Arr))
Case Else
Console.WriteLine("{2}{0}{1}{3}", vbNewLine, vbTab, "Computing Error!", "Need 2 Numbers or More for Computing.")
End Select


154105

سورس برنامه:

ROSTAM2
شنبه 30 مهر 1401, 16:29 عصر
برای بدست آوردن حجم اصلی فایل به بایت کافیه که از کلاس FileInfo از فضای نام IO استفاده کنید و خصوصیت Length مقدار بایت های حجم فایل را بر می گرداند:
154107
در این بخش یک آرایه داریم از نوع FileInfo که آدرس 3 تا فایل رو بصورت پیش فرض گرفته:

Dim Fio() As IO.FileInfo = {New IO.FileInfo("C:\Windows\System32\notepad.exe"), New IO.FileInfo("C:\Windows\System32\shell32.dll"), New IO.FileInfo("C:\Windows\System32\wmp.dll")}


هر کدوم از عناصر آرایه با حلقه For Each...Loop پیمایش می شن و حجم هر فایل در واحد های مختلف نمایش داده می شه:

For Each FI As IO.FileInfo In Fio
Dim FSI As New FileSizeInfo(FI.Length)
With FSI
Console.WriteLine()
Console.Write("{0}", vbTab)
Console.WriteLine("FileName: {0}", FI.Name)
Console.Write("{0}", vbTab)
Console.WriteLine("File Size: [{0} Bytes] - [{1} KB] - [{2} MB] - [{3} GB]", FormatNumber(.Bytes, 0, TriState.True, , TriState.True), FormatNumber(.KBytes, 3, TriState.True, , TriState.True), FormatNumber(.MBytes, 3, TriState.True, , TriState.True), FormatNumber(.GBytes, 3, TriState.True, , TriState.True))
End With
Next


برای بدست آوردن واحدهای مختلف اندازه فایل یک Structure داریم که با ایجاد یک متغیر از نوع جدید اون و ارائه دادن مقدار بایت های فایل به ورودی متود New همه واحد ها از طریق متغیر قابل دسترسی هستند:

Structure FileSizeInfo
Sub New(Len As Long)
BytesValue = Len
End Sub
Private BytesValue As Long
Public ReadOnly Property Bytes() As Long
Get
Return BytesValue
End Get
End Property
Public ReadOnly Property KBytes() As Double
Get
Dim Unit As Int16 = 1024
Return Me.Bytes / Unit
End Get
End Property
Public ReadOnly Property MBytes() As Double
Get
Dim Unit As Int32 = Math.Pow(1024, 2)
Return Me.Bytes / Unit
End Get
End Property
Public ReadOnly Property GBytes() As Double
Get
Dim Unit As Int32 = Math.Pow(1024, 3)
Return (Me.Bytes / Unit)
End Get
End Property
End Structure


*برای هر واحد بزرگتر از تابع Pow از کلاس Math از فضای نام System استفاده شده است*

سورس برنامه: (یک Console Application که با دستور Len ججم هر فایل که بصورت پیش فرض عناصر یک آرایه را تشکیل می دهند را نمایش می دهد)


154108

ROSTAM2
شنبه 21 آبان 1401, 19:33 عصر
سلام.
یک دیتاگرید داریم با یک ستون Id که ReadOnly هست و زمانی که مقدار قابل ویرایش رو درج می کنیم یک شماره باید به ستون فقط خواندنی باید اضافه بشه که در کل اون ستون باید منحصر به فرد باشه:

154182

اگر اعداد به فرض مثال از 101 شروع بشه بدست آوردن آخرین شماره که موردنیاز ردیف جدید از ستون Id هست.
ولی اگر یک یا چند ردیف از دیتاگرید حذف بشه اعدادی که قبلا داشتیم در از به همراه ردیف ها از ستون حذف می شه که ما می خوایم در زمان ایجاد ردیف جدید شماره ای به ما داده بشه که در بین اعداد حذف شده ستون هستند و در ستون وجود ندارند:

در این تصویر ردیف های حاوی شماره 102 و 104 حذف شده اند:

154183

اولین ردیف جدید باید شماره 102 و بعدی 104 و بعدی 106 و 107 و... داشته باشند:

154184

تابع DefaultNumber ابتدا بیشترین شماره موجود در ستون Id رو می گیره و با یک حلقه از StartRange شروع می کنه به پیمایش اعداد تا شماره Max اگر شماره Counter در ستون Id وجود نداشت شماره شمارنده بعنوان شماره پیشفرض بعنوان خروجی برگردانده می شود در غیر اینصورت اگر حلقه پایان یافت و همه شماره ها از StartRange تا Max در ستون Id موجود بود یک عدد به Max اضافه و بعنوان عدد پیشفرض برگردانده می شود:

Private Function DefaultNumber(Optional StartRange As Integer = 101) As Integer
Dim Number As Integer = StartRange
With Table
Dim Exist As Boolean = False
Dim Max% = .Compute("MAX([Id])", "")
Start: For i = Number To Max
Exist = CBool(.Compute("COUNT(Id)", String.Format("Id = {0}", i)) > 0)
If Exist = False Then
Return i
End If
Next
Number = Max + 1
End With
Return Number
End Function


اگر روش بهتری می شناسید در همین تاپیک به اشتراک بگذارید. با تشکر

mazoolagh
دوشنبه 23 آبان 1401, 17:02 عصر
سلام و روز خوش
در مورد "پیدا کردن نخستین ID پاک شده" چند مورد هست:

1- بنظر میاد این یک حالت خاص از یک مساله ریاضی "پیدا کردن شماره های پاک شده از بین یک سری شماره (مرتب یا نامرتب)" باشه.
من سناریویی به ذهنم نمیرسه این که id های پاک شده رو دوباره استفاده کنیم چه کاربرد عملی میتونه داشته باشه؛
ولی این که بعد از پاک کردن یک رکورد، idهای بعدی دوباره شماره گذاری بشن رو باهاش برخورد داشتم (هرچند که بنظرم کار نادرستی هست).

2- بنظر میاد کد هنوز جای بهینه شدن داشته باشه بخصوص که در هر اجرای حلقه یک compute هست.
در واقع اگر ID رکورد پاک شده اولی یا آخری باشه (یا اینکه اصلا هیچ رکوردی پاک نشده باشه) نیازی به اجرای حلقه نیست.

Function First_Missed_ID(ByRef table As DataTable, Optional seed As Long = 1) As Long
Dim Min_ID, Max_ID, Rows_Count As Long
table.DefaultView.Sort = "ID asc"
Dim tx As DataTable = table.DefaultView.ToTable()
Rows_Count = tx.Rows.Count
Min_ID = tx.Rows(0)("ID")
If Min_ID <> seed Then
Return seed
End If
Max_ID = tx.Rows(Rows_Count - 1)("ID")
If Max_ID = Min_ID + Rows_Count - 1 Then
Return Max_ID + 1
End If
For i = 0 To Rows_Count - 1
If tx.Rows(i)("ID") <> seed + i Then
Return seed + i
End If
Next
End Function

ROSTAM2
دوشنبه 23 آبان 1401, 19:34 عصر
سلام.
این که آی.دی های گم شده دوباره ایجاد بشن به پیدا کردن Id بصورت ذهنی بین اولین آی.دی و آخرین آی.دی کمک می کنه چرا که آی.دی ها مربوط به یک StringTable هست و مختص یک کامپوننت با عنوان StringProvider هست که در Designer به کمک یک Provide Property برای اشیا رشته رو از جدول فراخوانی می کنه با فرمتهای خاصی که یه کامپوننت داده شده. اینکه عددی یا اعدادی حذف شده باشه کاربر رو سردر گم می کنه البته این نظر منه. و اینکه تغییر آی.دی بصور دستی کاربر رو خسته می کنه. :متفکر:
گر چه من هنوز درگیر همین بخش Id هستم.

و این هم بگم که در String Table در ویرایشگر ریسورس VS آی.دی حذف شده بصورت خودکار برنمی گرده اما امکان ویرایش آی.دی هست شاید من زیاد سخت می گیرم ولی می خوام ابزرای که می سازم کارایی بهتری داشته باشه.

154199

mazoolagh
پنج شنبه 26 آبان 1401, 18:36 عصر
سلام دوباره
من فقط از جنبه ریاضی به این مورد نگاه کرده بودم و اونچه که در مورد string provider گفتین برای من تازگی داشت.

حالا مطمئن نیستم ولی این یک مورد خاص رو شاید استثنائا renumber کردن idها بعد از حذف یک رکورد بهتر باشه؛
چون همیشه نمیشه جای idهای خالی رو پر کرد و ممکنه باز هم چندتایی جای خالی داشته باشیم و خب بودن حتی 1 جای خالی فرقی با چند تا نداره و مقصود حاصل نمیشه.

ROSTAM2
پنج شنبه 26 آبان 1401, 20:09 عصر
سلام.

من برای این مورد تابع DefaultNumber رو به این صورت ویرایش کردم برای یک جدول خوبه:


Friend Function DefaultNumber(Table As DataTable, Optional StartRange As Integer = 101) As Integer
Dim Number As Integer = StartRange
With Table
If .Rows.Count = 0 Then Return StartRange
Dim Exist As Boolean = False
Dim Max% = .Compute("MAX([Id])", "")
If Max < StartRange Then Return StartRange
Start: For i = Number To Max
Exist = CBool(.Compute("COUNT(Id)", String.Format("Id = {0}", i)) > 0)
If Exist = False Then
Return i
End If
Next
Max += 1
Number = Max
End With
Return Number
End Function


اما من با یک چالش دیگه مواجه هستم. یک دیتاگرید دارم با 5 جدول متفاوت که فقط فیلد آی دیشون فیلد مشابه هست و بین این چند جدول باید جمع بندی داشته باشم یعنی اگر آی دی 101 در یک جدول باشه توی جدول های دیگه نباید وجود داشته باشه و همه جدولها باید بصورت یک مکمل عمل کنند چون در نهایت ردیف های تمام جدول ها با آی.دی ها به یک Dictionary اضافه می شن که Id باید منحصر به فرد باشه.

ROSTAM2
جمعه 27 آبان 1401, 15:30 عصر
سلام.
برای 5 RegistryHive جدول ایجاد شده که مجبور شدم محدوده اعداد رو از 101 تا 1101 تعیین کنم که محاسبه ساده تری داشته باشه: حالا بین این 5 تا جدول هر کدوم از این شماره ها جستجو می شه اگر در یکی جدول ها وجود داشت به عدد بعدی میره تا زمانی که عدد شمارنده در جدولها وجود نداشته باشه که بعنوان آی.دی جدید تعیین بشه:

ClassesRoot Table Rows:
154224

CurrentUser Table Rows:
154225

LocalMachine Table Rows:
154226

هم آی دی پیشفرض و هم آی دی حذف شده با این دستور بازیابی می شه:

Private Sub NewRowDefaultId(ParamArray Tables() As DataTable)
Dim RowIndex% = DataGrid1.CurrentRowIndex
Dim IdCellData As Object = Me.DataGrid1.Item(RowIndex, 0)
Dim Exist As Boolean = False
If IsDBNull(IdCellData) Then
Dim Id As Integer = 101
For i = 101 To 1101
For Each Table As DataTable In Tables
Exist = CBool(Table.Compute("COUNT(Id)", String.Format("Id = {0}", i)) > 0)
If Exist = True Then GoTo NextId
Next Table
Id = i
Exit For
NextId:
Next i
SetDefaultId:
If Id > 1101 Then
MsgBox("Id Range is Between 101 to 1101!", MsgBoxStyle.Exclamation)
Exit Sub
End If
IdColumn.ReadOnly = False
Me.DataGrid1(RowIndex, 0) = Id
IdColumn.ReadOnly = True
End If
End Sub